IOBlockStorageDriver.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/storage/IOBlockStorageDevice.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/storage/IOMedia.h>
#define super IOStorage
OSDefineMetaClassAndStructors(IOBlockStorageDriver, IOStorage)
const UInt32 kPollerInterval = 1000;
#define isMediaRemovable() (_removable)
static char * strclean(char * s)
{
int sourceIndex = 0, targetIndex = 0, targetLength = 0;
for ( ; s[sourceIndex] > '\0' && s[sourceIndex] <= ' '; sourceIndex++ );
for ( ; s[sourceIndex]; sourceIndex++ )
{
if ( s[sourceIndex] < '\0' || s[sourceIndex] >= ' ' )
{
if ( s[sourceIndex] != ' ' )
{
if ( targetLength < targetIndex )
{
targetIndex = targetLength + 1;
}
targetLength = targetIndex + 1;
}
s[targetIndex++] = s[sourceIndex];
}
}
s[targetLength] = '\0';
return s;
}
IOBlockStorageDevice * IOBlockStorageDriver::getProvider() const
{
return (IOBlockStorageDevice *) IOService::getProvider();
}
bool IOBlockStorageDriver::init(OSDictionary * properties = 0)
{
if (super::init(properties) == false) return false;
_expansionData = IONew(ExpansionData, 1);
if (_expansionData == 0) return false;
initMediaState();
_ejectable = false;
_lockable = false;
_pollIsExpensive = false;
_pollIsRequired = false;
_removable = false;
_mediaBlockSize = 0;
_maxBlockNumber = 0;
_maxReadBlockTransfer = 256;
_maxWriteBlockTransfer = 256;
_maxReadByteTransfer = 131072;
_maxWriteByteTransfer = 131072;
if (metaCast("IOCDBlockStorageDriver"))
{
_maxReadByteTransfer = 196608;
_maxWriteByteTransfer = 196608;
}
_mediaStateLock = IOLockAlloc();
if (_mediaStateLock == 0)
return false;
_deblockRequestWriteLock = IOLockAlloc();
_openClients = OSSet::withCapacity(2);
_pollerCall = thread_call_allocate(poller, this);
for (unsigned index = 0; index < kStatisticsCount; index++)
_statistics[index] = OSNumber::withNumber(0ULL, 64);
if (_deblockRequestWriteLock == 0 || _openClients == 0 || _pollerCall == 0)
return false;
for (unsigned index = 0; index < kStatisticsCount; index++)
if (_statistics[index] == 0) return false;
OSDictionary * statistics = OSDictionary::withCapacity(kStatisticsCount);
if (statistics == 0) return false;
statistics->setObject( kIOBlockStorageDriverStatisticsBytesReadKey,
_statistics[kStatisticsBytesRead] );
statistics->setObject( kIOBlockStorageDriverStatisticsBytesWrittenKey,
_statistics[kStatisticsBytesWritten] );
statistics->setObject( kIOBlockStorageDriverStatisticsReadErrorsKey,
_statistics[kStatisticsReadErrors] );
statistics->setObject( kIOBlockStorageDriverStatisticsWriteErrorsKey,
_statistics[kStatisticsWriteErrors] );
statistics->setObject( kIOBlockStorageDriverStatisticsLatentReadTimeKey,
_statistics[kStatisticsLatentReadTime] );
statistics->setObject( kIOBlockStorageDriverStatisticsLatentWriteTimeKey,
_statistics[kStatisticsLatentWriteTime] );
statistics->setObject( kIOBlockStorageDriverStatisticsReadsKey,
_statistics[kStatisticsReads] );
statistics->setObject( kIOBlockStorageDriverStatisticsWritesKey,
_statistics[kStatisticsWrites] );
statistics->setObject( kIOBlockStorageDriverStatisticsReadRetriesKey,
_statistics[kStatisticsReadRetries] );
statistics->setObject( kIOBlockStorageDriverStatisticsWriteRetriesKey,
_statistics[kStatisticsWriteRetries] );
statistics->setObject( kIOBlockStorageDriverStatisticsTotalReadTimeKey,
_statistics[kStatisticsTotalReadTime] );
statistics->setObject( kIOBlockStorageDriverStatisticsTotalWriteTimeKey,
_statistics[kStatisticsTotalWriteTime] );
setProperty(kIOBlockStorageDriverStatisticsKey, statistics);
return true;
}
bool IOBlockStorageDriver::start(IOService * provider)
{
if (provider->open(this) == false) return false;
if (handleStart(provider) == false)
{
provider->close(this);
return false;
}
if (isMediaRemovable() && isMediaPollRequired() && !isMediaPollExpensive())
{
lockForArbitration();
if (!isOpen() && !isInactive())
schedulePoller();
unlockForArbitration(); }
registerService();
return true;
}
bool IOBlockStorageDriver::yield(IOService * provider,
IOOptionBits options,
void * argument)
{
bool success = false;
lockForArbitration();
success = handleYield(provider, options, argument);
if (success)
{
provider->close(this);
}
unlockForArbitration();
return success;
}
void IOBlockStorageDriver::free()
{
if (_mediaStateLock) IOLockFree(_mediaStateLock);
if (_deblockRequestWriteLock) IOLockFree(_deblockRequestWriteLock);
if (_openClients) _openClients->release();
if (_pollerCall) thread_call_free(_pollerCall);
for (unsigned index = 0; index < kStatisticsCount; index++)
if (_statistics[index]) _statistics[index]->release();
if (_expansionData) IODelete(_expansionData, ExpansionData, 1);
super::free();
}
bool IOBlockStorageDriver::handleOpen(IOService * client,
IOOptionBits options,
void * argument)
{
assert(client);
if (getMediaState() == kIOMediaStateOffline) return false;
if (isMediaRemovable() && _openClients->getCount() == 0)
{
if (isMediaPollRequired() && !isMediaPollExpensive())
unschedulePoller();
if (lockMedia(true) != kIOReturnSuccess)
IOLog("%s: Unable to lock down removable media.\n", getName());
}
_openClients->setObject(client);
return true;
}
bool IOBlockStorageDriver::handleIsOpen(const IOService * client) const
{
if (client)
return _openClients->containsObject(client);
else
return (_openClients->getCount() != 0);
}
void IOBlockStorageDriver::handleClose(IOService * client, IOOptionBits options)
{
assert(client);
_openClients->removeObject(client);
if (!isInactive() && _openClients->getCount() == 0)
{
if (isMediaWritable())
{
if (getMediaState() == kIOMediaStateOnline)
{
if (synchronizeCache(this) != kIOReturnSuccess)
IOLog("%s: Unable to flush cache on media.\n", getName());
}
}
if (isMediaRemovable())
{
if (getMediaState() == kIOMediaStateOnline)
{
if (lockMedia(false) != kIOReturnSuccess)
IOLog("%s: Unable to unlock removable media.\n", getName());
}
if (isMediaPollRequired() && !isMediaPollExpensive())
schedulePoller(); }
}
}
void IOBlockStorageDriver::read(IOService * ,
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageCompletion completion)
{
assert(buffer->getDirection() == kIODirectionIn);
prepareRequest(byteStart, buffer, completion);
}
void IOBlockStorageDriver::write(IOService * ,
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageCompletion completion)
{
assert(buffer->getDirection() == kIODirectionOut);
prepareRequest(byteStart, buffer, completion);
}
void IOBlockStorageDriver::addToBytesTransferred(UInt64 bytesTransferred,
UInt64 totalTime, UInt64 latentTime, bool isWrite)
{
if (isWrite)
{
_statistics[kStatisticsWrites]->addValue(1);
_statistics[kStatisticsBytesWritten]->addValue(bytesTransferred);
_statistics[kStatisticsTotalWriteTime]->addValue(totalTime);
_statistics[kStatisticsLatentWriteTime]->addValue(latentTime);
if (bytesTransferred <= getMediaBlockSize())
_statistics[kStatisticsSingleBlockWrites]->addValue(1);
}
else
{
_statistics[kStatisticsReads]->addValue(1);
_statistics[kStatisticsBytesRead]->addValue(bytesTransferred);
_statistics[kStatisticsTotalReadTime]->addValue(totalTime);
_statistics[kStatisticsLatentReadTime]->addValue(latentTime);
}
}
void IOBlockStorageDriver::incrementRetries(bool isWrite)
{
if (isWrite)
_statistics[kStatisticsWriteRetries]->addValue(1);
else
_statistics[kStatisticsReadRetries]->addValue(1);
}
void IOBlockStorageDriver::incrementErrors(bool isWrite)
{
if (isWrite)
_statistics[kStatisticsWriteErrors]->addValue(1);
else
_statistics[kStatisticsReadErrors]->addValue(1);
}
UInt32 IOBlockStorageDriver::getStatistics(UInt64 * statistics,
UInt32 statisticsMaxCount) const
{
if (statistics == 0)
return kStatisticsCount;
UInt32 statisticsCount = min(kStatisticsCount, statisticsMaxCount);
for (unsigned index = 0; index < statisticsCount; index++)
statistics[index] = _statistics[index]->unsigned64BitValue();
return statisticsCount;
}
UInt64 IOBlockStorageDriver::getStatistic(Statistics statistic) const
{
if ((UInt32) statistic >= kStatisticsCount) return 0;
return _statistics[statistic]->unsigned64BitValue();
}
IOBlockStorageDriver::Context * IOBlockStorageDriver::allocateContext()
{
Context * context = IONew(Context, 1);
if (context)
{
bzero(context, sizeof(Context));
}
return context;
}
void IOBlockStorageDriver::deleteContext(
IOBlockStorageDriver::Context * context)
{
IODelete(context, Context, 1);
}
void IOBlockStorageDriver::prepareRequest(UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageCompletion completion)
{
Context * context;
context = allocateContext();
if (context == 0)
{
complete(completion, kIOReturnNoMemory);
return;
}
context->block.size = getMediaBlockSize();
context->block.type = kBlockTypeStandard;
context->original.byteStart = byteStart;
context->original.buffer = buffer;
context->original.buffer->retain();
context->original.completion = completion;
completion.target = this;
completion.action = prepareRequestCompletion;
completion.parameter = context;
deblockRequest(byteStart, buffer, completion, context);
}
void IOBlockStorageDriver::prepareRequestCompletion(void * target,
void * parameter,
IOReturn status,
UInt64 actualByteCount)
{
Context * context = (Context *) parameter;
IOBlockStorageDriver * driver = (IOBlockStorageDriver *) target;
bool isWrite;
isWrite = (context->original.buffer->getDirection() == kIODirectionOut);
assert(status != kIOReturnSuccess ||
context->original.buffer->getLength() == actualByteCount);
driver->addToBytesTransferred(actualByteCount, 0, 0, isWrite);
if (status != kIOReturnSuccess)
{
driver->incrementErrors(isWrite);
}
IOStorage::complete(context->original.completion, status, actualByteCount);
context->original.buffer->release();
driver->deleteContext(context);
}
void IOBlockStorageDriver::schedulePoller()
{
AbsoluteTime deadline;
retain();
clock_interval_to_deadline(kPollerInterval, kMillisecondScale, &deadline);
thread_call_enter_delayed(_pollerCall, deadline);
}
void IOBlockStorageDriver::unschedulePoller()
{
if (thread_call_cancel(_pollerCall)) release();
}
void IOBlockStorageDriver::poller(void * target, void *)
{
IOBlockStorageDriver * driver = (IOBlockStorageDriver *) target;
driver->pollMedia();
driver->lockForArbitration();
if (!driver->isOpen() && !driver->isInactive())
driver->schedulePoller();
driver->unlockForArbitration();
driver->release(); }
IOReturn IOBlockStorageDriver::message(UInt32 type,
IOService * provider,
void * argument)
{
switch (type)
{
case kIOMessageMediaStateHasChanged:
{
IOReturn status;
IOLockLock(_mediaStateLock);
status = mediaStateHasChanged((IOMediaState) argument);
IOLockUnlock(_mediaStateLock);
return status;
}
case kIOMessageServiceIsRequestingClose:
{
bool success;
success = yield(provider, 0, argument);
return success ? kIOReturnSuccess : kIOReturnBusy;
}
case kIOMessageServiceIsTerminated:
{
bool success;
success = yield(provider, kIOServiceRequired, argument);
return success ? kIOReturnSuccess : kIOReturnError;
}
default:
{
return super::message(type, provider, argument);
}
}
}
IOReturn
IOBlockStorageDriver::acceptNewMedia(void)
{
IOReturn result;
bool ok;
UInt64 nbytes;
char name[128];
bool nameSep;
#ifdef moreDebug
IOLog("%s[IOBlockStorageDriver]::%s media: %ld blocks, %ld bytes each, write-%s.\n",
getName(),
getDeviceTypeName(),
(UInt32)_maxBlockNumber + 1,(UInt32)getMediaBlockSize(),
(_writeProtected ? "protected" : "enabled"));
#endif
if (_maxBlockNumber) {
nbytes = _mediaBlockSize * (_maxBlockNumber + 1);
} else {
nbytes = 0;
}
name[0] = 0;
nameSep = false;
if (getProvider()->getVendorString()) {
strcat(name, getProvider()->getVendorString());
nameSep = true;
}
if (getProvider()->getProductString()) {
if (nameSep == true) strcat(name, " ");
strcat(name, getProvider()->getProductString());
nameSep = true;
}
if (nameSep == true) strcat(name, " ");
strcat(name, "Media");
strclean(name);
_mediaObject = instantiateMediaObject(0,nbytes,_mediaBlockSize,name);
result = (_mediaObject) ? kIOReturnSuccess : kIOReturnBadArgument;
if (result == kIOReturnSuccess) {
ok = _mediaObject->attach(this);
if (ok) {
_mediaPresent = true;
_mediaObject->registerService();
} else {
_mediaObject->release();
_mediaObject = 0;
return(kIOReturnNoMemory);
}
}
return(result);
}
IOReturn
IOBlockStorageDriver::checkForMedia(void)
{
IOReturn result;
bool currentState;
bool changed;
IOLockLock(_mediaStateLock);
result = getProvider()->reportMediaState(¤tState,&changed);
if (result != kIOReturnSuccess) {
IOLog("%s[IOBlockStorageDriver]::checkForMedia; err '%s' from reportMediaState\n",
getName(),stringFromReturn(result));
} else if (changed) {
result = mediaStateHasChanged(currentState ? kIOMediaStateOnline
: kIOMediaStateOffline);
}
IOLockUnlock(_mediaStateLock);
return(result);
}
IOReturn
IOBlockStorageDriver::mediaStateHasChanged(IOMediaState state)
{
IOReturn result;
if (state == kIOMediaStateOnline) {
if (validateNewMedia() == false) {
rejectMedia();
return(kIOReturnSuccess);
}
result = recordMediaParameters();
if (result != kIOReturnSuccess) {
initMediaState();
IOLog("%s[IOBlockStorageDriver]::checkForMedia: err '%s' from recordMediaParameters\n",
getName(),stringFromReturn(result));
return(result);
}
lockForArbitration();
result = acceptNewMedia();
if (result != kIOReturnSuccess) {
initMediaState();
IOLog("%s[IOBlockStorageDriver]::checkForMedia; err '%s' from acceptNewMedia\n",
getName(),stringFromReturn(result));
}
unlockForArbitration();
return(result);
} else {
lockForArbitration();
result = decommissionMedia(true);
unlockForArbitration();
if (result != kIOReturnSuccess && result != kIOReturnNoMedia) {
IOLog("%s[IOBlockStorageDriver]::checkForMedia; err '%s' from decommissionNewMedia\n",
getName(),stringFromReturn(result));
return(result);
}
return(kIOReturnSuccess);
}
}
UInt64
IOBlockStorageDriver::constrainByteCount(UInt64 ,bool isWrite)
{
if (isWrite) {
return(_maxWriteByteTransfer);
} else {
return(_maxReadByteTransfer);
}
}
IOReturn
IOBlockStorageDriver::decommissionMedia(bool forcible)
{
IOReturn result;
if (_mediaObject) {
if (_mediaObject->terminate(forcible ? kIOServiceRequired : 0) || forcible) {
_mediaObject->release();
_mediaObject = 0;
initMediaState();
result = kIOReturnSuccess;
} else {
result = kIOReturnBusy;
}
} else {
result = kIOReturnNoMedia;
}
return(result);
}
IOReturn
IOBlockStorageDriver::ejectMedia(void)
{
IOReturn result;
if (_ejectable) {
IOLockLock(_mediaStateLock);
lockForArbitration();
result = decommissionMedia(false);
unlockForArbitration();
if (result == kIOReturnSuccess) {
if (lockMedia(false) != kIOReturnSuccess)
IOLog("%s: Unable to unlock removable media.\n", getName());
(void)getProvider()->doEjectMedia();
}
IOLockUnlock(_mediaStateLock);
return(result);
} else {
return(kIOReturnUnsupported);
}
}
void
IOBlockStorageDriver::executeRequest(UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageCompletion completion,
IOBlockStorageDriver::Context * context)
{
UInt32 block;
UInt32 nblks;
IOReturn result;
if (!_mediaPresent) {
complete(completion, kIOReturnNoMedia,0);
return;
}
assert((byteStart % _mediaBlockSize) == 0);
assert((buffer->getLength() % _mediaBlockSize) == 0);
block = byteStart / _mediaBlockSize;
nblks = buffer->getLength() / _mediaBlockSize;
result = getProvider()->doAsyncReadWrite(buffer,block,nblks,completion);
if (result != kIOReturnSuccess) {
IOLog("%s[IOBlockStorageDriver]; executeRequest: request failed to start!\n",getName());
complete(completion,result);
return;
}
}
IOReturn
IOBlockStorageDriver::formatMedia(UInt64 byteCapacity)
{
if (!_mediaPresent) {
return(kIOReturnNoMedia);
}
return(getProvider()->doFormatMedia(byteCapacity));
}
const char *
IOBlockStorageDriver::getDeviceTypeName(void)
{
return(kIOBlockStorageDeviceTypeGeneric);
}
UInt32
IOBlockStorageDriver::getFormatCapacities(UInt64 * capacities,
UInt32 capacitiesMaxCount) const
{
return(getProvider()->doGetFormatCapacities(capacities,capacitiesMaxCount));
}
UInt64
IOBlockStorageDriver::getMediaBlockSize() const
{
return(_mediaBlockSize);
}
IOMediaState
IOBlockStorageDriver::getMediaState() const
{
if (_mediaPresent) {
return(kIOMediaStateOnline);
} else {
return(kIOMediaStateOffline);
}
}
bool
IOBlockStorageDriver::handleStart(IOService * provider)
{
IOReturn result;
OSNumber * maxBlockCountRead;
OSNumber * maxBlockCountWrite;
OSNumber * maxSegmentCountRead;
OSNumber * maxSegmentCountWrite;
result = getProvider()->reportRemovability(&_removable);
if (result != kIOReturnSuccess) {
IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportRemovability\n",
getName(),stringFromReturn(result));
return(false);
}
if (_removable) {
result = getProvider()->reportPollRequirements(&_pollIsRequired,&_pollIsExpensive);
if (result != kIOReturnSuccess) {
IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportPollRequirements\n",
getName(),stringFromReturn(result));
return(false);
}
result = getProvider()->reportEjectability(&_ejectable);
if (result != kIOReturnSuccess) {
IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportEjectability\n",
getName(),stringFromReturn(result));
return(false);
}
result = getProvider()->reportLockability(&_lockable);
if (result != kIOReturnSuccess) {
IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportLockability\n",
getName(),stringFromReturn(result));
return(false);
}
} else {
_ejectable = false;
_lockable = false;
_pollIsRequired = true;
}
maxBlockCountRead = OSDynamicCast(
OSNumber,
getProperty(
kIOMaximumBlockCountReadKey,
gIOServicePlane ) );
maxBlockCountWrite = OSDynamicCast(
OSNumber,
getProperty(
kIOMaximumBlockCountWriteKey,
gIOServicePlane ) );
maxSegmentCountRead = OSDynamicCast(
OSNumber,
getProperty(
kIOMaximumSegmentCountReadKey,
gIOServicePlane ) );
maxSegmentCountWrite = OSDynamicCast(
OSNumber,
getProperty(
kIOMaximumSegmentCountWriteKey,
gIOServicePlane ) );
if ( maxBlockCountRead == 0 || maxBlockCountWrite == 0 )
{
UInt64 maxReadTransfer;
UInt64 maxWriteTransfer;
result = getProvider()->reportMaxReadTransfer(512, &maxReadTransfer);
if (result == kIOReturnSuccess)
{
_maxReadBlockTransfer = maxReadTransfer / 512;
_maxReadBlockTransfer = min(_maxReadBlockTransfer, 0xFFFFFFFF);
_maxReadBlockTransfer = min(_maxReadBlockTransfer, 0x7FFFF);
}
result = getProvider()->reportMaxWriteTransfer(512, &maxWriteTransfer);
if (result == kIOReturnSuccess)
{
_maxWriteBlockTransfer = maxWriteTransfer / 512;
_maxWriteBlockTransfer = min(_maxWriteBlockTransfer, 0xFFFFFFFF);
_maxWriteBlockTransfer = min(_maxWriteBlockTransfer, 0x7FFFF);
}
}
if ( maxBlockCountRead )
{
_maxReadBlockTransfer = maxBlockCountRead->unsigned64BitValue();
_maxReadBlockTransfer = min(_maxReadBlockTransfer, 0xFFFFFFFF);
}
else
{
getProvider()->setProperty(
kIOMaximumBlockCountReadKey,
_maxReadBlockTransfer, 64);
}
if ( maxBlockCountWrite )
{
_maxWriteBlockTransfer = maxBlockCountWrite->unsigned64BitValue();
_maxWriteBlockTransfer = min(_maxWriteBlockTransfer, 0xFFFFFFFF);
}
else
{
getProvider()->setProperty(
kIOMaximumBlockCountWriteKey,
_maxWriteBlockTransfer, 64);
}
if ( maxSegmentCountRead )
{
_maxReadByteTransfer = maxSegmentCountRead->unsigned64BitValue();
_maxReadByteTransfer = min(_maxReadByteTransfer, 0xFFFFFFFF);
_maxReadByteTransfer = _maxReadByteTransfer * page_size;
}
else
{
getProvider()->setProperty(
kIOMaximumSegmentCountReadKey,
_maxReadByteTransfer / page_size, 64);
}
if ( maxSegmentCountWrite )
{
_maxWriteByteTransfer = maxSegmentCountWrite->unsigned64BitValue();
_maxWriteByteTransfer = min(_maxWriteByteTransfer, 0xFFFFFFFF);
_maxWriteByteTransfer = _maxWriteByteTransfer * page_size;
}
else
{
getProvider()->setProperty(
kIOMaximumSegmentCountWriteKey,
_maxWriteByteTransfer / page_size, 64);
}
if ( _maxReadBlockTransfer == 0 ) _maxReadBlockTransfer = 0xFFFFFFFF;
if ( _maxWriteBlockTransfer == 0 ) _maxWriteBlockTransfer = 0xFFFFFFFF;
if ( _maxReadByteTransfer == 0 ) _maxReadByteTransfer = 0xFFFFFFFF;
if ( _maxWriteByteTransfer == 0 ) _maxWriteByteTransfer = 0xFFFFFFFF;
result = checkForMedia();
if (result != kIOReturnSuccess && !_removable) {
IOLog("%s[IOBlockStorageDriver]::handleStart: err '%s' from checkForMedia\n",
getName(),stringFromReturn(result));
return(false);
}
return(true);
}
bool
IOBlockStorageDriver::handleYield(IOService * provider,
IOOptionBits options,
void * argument)
{
if ( (options & kIOServiceRequired) == 0 && isOpen() != false )
{
return false;
}
if ( isMediaRemovable() != false &&
isMediaPollRequired() != false &&
isMediaPollExpensive() == false )
{
unschedulePoller(); }
decommissionMedia(true);
return true;
}
void
IOBlockStorageDriver::initMediaState(void)
{
_mediaDirtied = false;
_mediaPresent = false;
_writeProtected = false;
}
IOMedia *
IOBlockStorageDriver::instantiateDesiredMediaObject(void)
{
return(new IOMedia);
}
IOMedia *
IOBlockStorageDriver::instantiateMediaObject(UInt64 base,UInt64 byteSize,
UInt32 blockSize,char *mediaName)
{
IOMedia *m;
bool result;
m = instantiateDesiredMediaObject();
if (m == NULL) {
return(NULL);
}
result = m->init( base,
byteSize,
blockSize,
_ejectable,
true,
!_writeProtected,
"");
if (result) {
m->setName(mediaName);
return(m);
} else {
m->release();
return(NULL);
}
}
bool
IOBlockStorageDriver::isMediaEjectable(void) const
{
return(_ejectable);
}
bool
IOBlockStorageDriver::isMediaPollExpensive(void) const
{
return(_pollIsExpensive);
}
bool
IOBlockStorageDriver::isMediaPollRequired(void) const
{
return(_pollIsRequired);
}
bool
IOBlockStorageDriver::isMediaWritable(void) const
{
return(!_writeProtected);
}
IOReturn
IOBlockStorageDriver::lockMedia(bool locked)
{
if (_lockable) {
return(getProvider()->doLockUnlockMedia(locked));
} else {
return(kIOReturnUnsupported);
}
}
IOReturn
IOBlockStorageDriver::pollMedia(void)
{
if (!_pollIsRequired) {
return(kIOReturnUnsupported);
} else {
return(checkForMedia());
}
}
IOReturn
IOBlockStorageDriver::recordMediaParameters(void)
{
IOReturn result;
result = getProvider()->reportBlockSize(&_mediaBlockSize);
if (result != kIOReturnSuccess) {
goto err;
}
result = getProvider()->reportMaxValidBlock(&_maxBlockNumber);
if (result != kIOReturnSuccess) {
goto err;
}
result = getProvider()->reportWriteProtection(&_writeProtected);
if (result != kIOReturnSuccess) {
goto err;
}
return(kIOReturnSuccess);
err:
_mediaPresent = false;
_writeProtected = true;
return(result);
}
void
IOBlockStorageDriver::rejectMedia(void)
{
(void)getProvider()->doEjectMedia();
initMediaState();
}
IOReturn
IOBlockStorageDriver::synchronizeCache(IOService *client)
{
return(getProvider()->doSynchronizeCache());
}
bool
IOBlockStorageDriver::validateNewMedia(void)
{
return(true);
}
#include <IOKit/IOBufferMemoryDescriptor.h>
class IODeblocker : public IOMemoryDescriptor
{
OSDeclareDefaultStructors(IODeblocker);
protected:
UInt64 _blockSize;
struct
{
IOMemoryDescriptor * buffer;
UInt32 offset;
UInt32 length;
} _chunks[3];
UInt32 _chunksCount;
IOBufferMemoryDescriptor * _excessBuffer;
UInt64 _excessCountFinal;
UInt64 _excessCountStart;
IOMemoryDescriptor * _requestBuffer;
IOStorageCompletion _requestCompletion;
void * _requestContext;
UInt64 _requestCount;
bool _requestIsOneBlock;
UInt64 _requestStart;
enum
{
kStageInit,
kStagePrepareExcessStart,
kStagePrepareExcessFinal,
kStageLast,
kStageDone
} _stage;
virtual void free();
virtual bool initWithAddress( void * address,
IOByteCount withLength,
IODirection withDirection );
virtual bool initWithAddress( vm_address_t address,
IOByteCount withLength,
IODirection withDirection,
task_t withTask );
virtual bool initWithPhysicalAddress(
IOPhysicalAddress address,
IOByteCount withLength,
IODirection withDirection );
virtual bool initWithPhysicalRanges(
IOPhysicalRange * ranges,
UInt32 withCount,
IODirection withDirection,
bool asReference = false );
virtual bool initWithRanges( IOVirtualRange * ranges,
UInt32 withCount,
IODirection withDirection,
task_t withTask,
bool asReference = false );
virtual void * getVirtualSegment( IOByteCount offset,
IOByteCount * length );
IOMemoryDescriptor::withAddress;
IOMemoryDescriptor::withPhysicalAddress;
IOMemoryDescriptor::withPhysicalRanges;
IOMemoryDescriptor::withRanges;
IOMemoryDescriptor::withSubRange;
public:
static IODeblocker * withBlockSize(
UInt64 blockSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext );
virtual bool initWithBlockSize(
UInt64 blockSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext );
virtual IOPhysicalAddress getPhysicalSegment( IOByteCount offset,
IOByteCount * length );
virtual IOReturn prepare(IODirection forDirection = kIODirectionNone);
virtual IOReturn complete(IODirection forDirection = kIODirectionNone);
virtual IOByteCount readBytes( IOByteCount offset,
void * bytes,
IOByteCount withLength );
virtual IOByteCount writeBytes( IOByteCount offset,
const void * bytes,
IOByteCount withLength );
virtual bool getNextStage(UInt64 * byteStart);
virtual void getRequestCompletion( IOStorageCompletion * completion,
IOReturn * status,
UInt64 * actualByteCount );
virtual IOMemoryDescriptor * getRequestBuffer();
virtual void * getRequestContext();
};
#undef super
#define super IOMemoryDescriptor
OSDefineMetaClassAndStructors(IODeblocker, IOMemoryDescriptor)
bool IODeblocker::initWithAddress( void * ,
IOByteCount ,
IODirection )
{
return false;
}
bool IODeblocker::initWithAddress( vm_address_t ,
IOByteCount ,
IODirection ,
task_t )
{
return false;
}
bool IODeblocker::initWithPhysicalAddress(
IOPhysicalAddress ,
IOByteCount ,
IODirection )
{
return false;
}
bool IODeblocker::initWithPhysicalRanges(
IOPhysicalRange * ,
UInt32 ,
IODirection ,
bool )
{
return false;
}
bool IODeblocker::initWithRanges( IOVirtualRange * ,
UInt32 ,
IODirection ,
task_t ,
bool )
{
return false;
}
IODeblocker * IODeblocker::withBlockSize(
UInt64 blockSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext )
{
IODeblocker * me = new IODeblocker;
if ( me && me->initWithBlockSize(
blockSize,
withRequestStart,
withRequestBuffer,
withRequestCompletion,
withRequestContext ) == false )
{
me->release();
me = 0;
}
return me;
}
bool IODeblocker::initWithBlockSize(
UInt64 blockSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext )
{
UInt32 excessBufferSize = 0;
if ( super::init() == false ) return false;
_blockSize = blockSize;
_chunksCount = 0;
_direction = kIODirectionNone;
_length = 0;
_requestBuffer = withRequestBuffer;
_requestBuffer->retain();
_requestCompletion = withRequestCompletion;
_requestContext = withRequestContext;
_requestCount = withRequestBuffer->getLength();
_requestStart = withRequestStart;
_excessCountStart = (withRequestStart ) % blockSize;
_excessCountFinal = (withRequestStart + _requestCount) % blockSize;
if ( _excessCountFinal ) _excessCountFinal = blockSize - _excessCountFinal;
_requestIsOneBlock = (_excessCountStart + _requestCount <= blockSize);
switch ( _requestBuffer->getDirection() )
{
case kIODirectionIn: {
excessBufferSize = max(_excessCountStart, _excessCountFinal);
} break;
case kIODirectionOut: {
if ( _excessCountStart ) excessBufferSize += blockSize;
if ( _excessCountFinal ) excessBufferSize += blockSize;
if ( _excessCountStart && _excessCountFinal && _requestIsOneBlock )
{
excessBufferSize -= blockSize;
}
} break;
default:
{
assert(0);
} break;
}
if ( excessBufferSize )
{
_excessBuffer = IOBufferMemoryDescriptor::withCapacity(
excessBufferSize,
kIODirectionNone );
if ( _excessBuffer == 0 ) return false;
}
return true;
}
void IODeblocker::free()
{
if ( _requestBuffer ) _requestBuffer->release();
if ( _excessBuffer ) _excessBuffer->release();
super::free();
}
IOReturn IODeblocker::prepare(IODirection forDirection)
{
unsigned index;
IOReturn status = kIOReturnInternalError;
IOReturn statusUndo;
if ( forDirection == kIODirectionNone )
{
forDirection = _direction;
}
for ( index = 0; index < _chunksCount; index++ )
{
status = _chunks[index].buffer->prepare(forDirection);
if ( status != kIOReturnSuccess ) break;
}
if ( status != kIOReturnSuccess )
{
for ( unsigned indexUndo = 0; indexUndo <= index; indexUndo++ )
{
statusUndo = _chunks[index].buffer->complete(forDirection);
assert(statusUndo == kIOReturnSuccess);
}
}
return status;
}
IOReturn IODeblocker::complete(IODirection forDirection)
{
IOReturn status;
IOReturn statusFinal = kIOReturnSuccess;
if ( forDirection == kIODirectionNone )
{
forDirection = _direction;
}
for ( unsigned index = 0; index < _chunksCount; index++ )
{
status = _chunks[index].buffer->complete(forDirection);
if ( status != kIOReturnSuccess ) statusFinal = status;
assert(status == kIOReturnSuccess);
}
return statusFinal;
}
IOPhysicalAddress IODeblocker::getPhysicalSegment( IOByteCount offset,
IOByteCount * length )
{
assert(offset <= _length);
for ( unsigned index = 0; index < _chunksCount; index++ )
{
if ( offset < _chunks[index].length )
{
IOPhysicalAddress address;
address = _chunks[index].buffer->getPhysicalSegment(
offset + _chunks[index].offset,
length );
if ( length ) *length = min(*length, _chunks[index].length);
return address;
}
offset -= _chunks[index].length;
}
if ( length ) *length = 0;
return 0;
}
void * IODeblocker::getVirtualSegment( IOByteCount ,
IOByteCount * )
{
return 0;
}
IOByteCount IODeblocker::readBytes( IOByteCount offset,
void * bytes,
IOByteCount withLength )
{
IOByteCount bytesCopied = 0;
unsigned index;
for ( index = 0; index < _chunksCount; index++ )
{
if ( offset < _chunks[index].length ) break;
offset -= _chunks[index].length;
}
for ( ; index < _chunksCount && withLength; index++)
{
IOByteCount copy = min(_chunks[index].length - offset, withLength);
IOByteCount copied = _chunks[index].buffer->readBytes(
offset + _chunks[index].offset,
bytes,
copy );
bytesCopied += copied;
if ( copied != copy ) break;
bytes = ((UInt8 *) bytes) + copied;
withLength -= copied;
offset = 0;
}
return bytesCopied;
}
IOByteCount IODeblocker::writeBytes( IOByteCount offset,
const void * bytes,
IOByteCount withLength )
{
IOByteCount bytesCopied = 0;
unsigned index;
for ( index = 0; index < _chunksCount; index++ )
{
if ( offset < _chunks[index].length ) break;
offset -= _chunks[index].length;
}
for ( ; index < _chunksCount && withLength; index++)
{
IOByteCount copy = min(_chunks[index].length - offset, withLength);
IOByteCount copied = _chunks[index].buffer->writeBytes(
offset + _chunks[index].offset,
bytes,
copy );
bytesCopied += copied;
if ( copied != copy ) break;
bytes = ((UInt8 *) bytes) + copied;
withLength -= copied;
offset = 0;
}
return bytesCopied;
}
bool IODeblocker::getNextStage(UInt64 * byteStart)
{
_chunksCount = 0;
_direction = kIODirectionNone;
_length = 0;
switch ( _requestBuffer->getDirection() )
{
case kIODirectionIn: {
switch ( _stage )
{
case kStageInit:
{
_stage = kStageLast;
_excessBuffer->setDirection(kIODirectionIn);
_direction = kIODirectionIn;
*byteStart = _requestStart - _excessCountStart;
if ( _excessCountStart )
{
_chunks[_chunksCount].buffer = _excessBuffer;
_chunks[_chunksCount].offset = 0;
_chunks[_chunksCount].length = _excessCountStart;
_chunksCount++;
}
_chunks[_chunksCount].buffer = _requestBuffer;
_chunks[_chunksCount].offset = 0;
_chunks[_chunksCount].length = _requestBuffer->getLength();
_chunksCount++;
if ( _excessCountFinal )
{
_chunks[_chunksCount].buffer = _excessBuffer;
_chunks[_chunksCount].offset = 0;
_chunks[_chunksCount].length = _excessCountFinal;
_chunksCount++;
}
} break;
case kStageLast:
{
_stage = kStageDone;
} break;
default:
{
assert(0);
} break;
} } break;
case kIODirectionOut: {
switch ( _stage )
{
case kStageInit:
{
if ( _excessCountStart )
{
_stage = kStagePrepareExcessStart;
_excessBuffer->setDirection(kIODirectionIn);
_direction = kIODirectionIn;
*byteStart = _requestStart - _excessCountStart;
_chunks[_chunksCount].buffer = _excessBuffer;
_chunks[_chunksCount].offset = 0;
_chunks[_chunksCount].length = _blockSize;
_chunksCount++;
break;
}
}
case kStagePrepareExcessStart:
{
if ( _excessCountFinal )
{
if ( !_excessCountStart || !_requestIsOneBlock )
{
_stage = kStagePrepareExcessFinal;
_excessBuffer->setDirection(kIODirectionIn);
_direction = kIODirectionIn;
*byteStart = _requestStart + _requestCount +
_excessCountFinal - _blockSize;
_chunks[_chunksCount].buffer = _excessBuffer;
_chunks[_chunksCount].offset = (_requestIsOneBlock)
? 0
: (_excessCountStart)
? _blockSize
: 0;
_chunks[_chunksCount].length = _blockSize;
_chunksCount++;
break;
}
}
}
case kStagePrepareExcessFinal:
{
_stage = kStageLast;
_excessBuffer->setDirection(kIODirectionOut);
_direction = kIODirectionOut;
*byteStart = _requestStart - _excessCountStart;
if ( _excessCountStart )
{
_chunks[_chunksCount].buffer = _excessBuffer;
_chunks[_chunksCount].offset = 0;
_chunks[_chunksCount].length = _excessCountStart;
_chunksCount++;
}
_chunks[_chunksCount].buffer = _requestBuffer;
_chunks[_chunksCount].offset = 0;
_chunks[_chunksCount].length = _requestBuffer->getLength();
_chunksCount++;
if ( _excessCountFinal )
{
_chunks[_chunksCount].buffer = _excessBuffer;
_chunks[_chunksCount].offset = (_requestIsOneBlock)
? 0
: (_excessCountStart)
? _blockSize
: 0;
_chunks[_chunksCount].offset += ( _blockSize -
_excessCountFinal );
_chunks[_chunksCount].length = _excessCountFinal;
_chunksCount++;
}
} break;
case kStageLast:
{
_stage = kStageDone;
} break;
default:
{
assert(0);
} break;
} } break;
default:
{
assert(0);
} break;
}
if ( _chunksCount == 0 ) return false;
for ( unsigned index = 0; index < _chunksCount; index++ )
{
_length += _chunks[index].length;
}
return true;
}
void IODeblocker::getRequestCompletion( IOStorageCompletion * completion,
IOReturn * status,
UInt64 * actualByteCount )
{
*completion = _requestCompletion;
switch ( _stage )
{
case kStageInit: {
*status = kIOReturnInternalError;
*actualByteCount = 0;
} break;
case kStagePrepareExcessStart: case kStagePrepareExcessFinal:
{
*actualByteCount = 0;
} break;
case kStageLast: case kStageDone:
{
if ( *actualByteCount > _excessCountStart )
*actualByteCount -= _excessCountStart;
else
*actualByteCount = 0;
if ( *actualByteCount > _requestBuffer->getLength() )
*actualByteCount = _requestBuffer->getLength();
} break;
default:
{
assert(0);
} break;
}
}
IOMemoryDescriptor * IODeblocker::getRequestBuffer()
{
return _requestBuffer;
}
void * IODeblocker::getRequestContext()
{
return _requestContext;
}
void IOBlockStorageDriver::deblockRequest(
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageCompletion completion,
IOBlockStorageDriver::Context * context )
{
IODeblocker * deblocker;
if ( (byteStart % context->block.size) == 0 &&
(buffer->getLength() % context->block.size) == 0 )
{
breakUpRequest(byteStart, buffer, completion, context);
return;
}
deblocker = IODeblocker::withBlockSize(
context->block.size,
byteStart,
buffer,
completion,
context );
if ( deblocker == 0 )
{
complete(completion, kIOReturnNoMemory);
return;
}
if ( buffer->getDirection() == kIODirectionOut )
{
IOLockLock(_deblockRequestWriteLock);
}
deblockRequestCompletion(this, deblocker, kIOReturnSuccess, 0);
return;
}
void IOBlockStorageDriver::deblockRequestCompletion( void * target,
void * parameter,
IOReturn status,
UInt64 actualByteCount )
{
UInt64 byteStart;
IOStorageCompletion completion;
Context * context;
IODeblocker * deblocker = (IODeblocker *) parameter;
IOBlockStorageDriver * driver = (IOBlockStorageDriver *) target;
if ( actualByteCount < deblocker->getLength() ||
status != kIOReturnSuccess ||
deblocker->getNextStage(&byteStart) == false )
{
if ( deblocker->getRequestBuffer()->getDirection() == kIODirectionOut )
{
IOLockUnlock(driver->_deblockRequestWriteLock);
}
deblocker->getRequestCompletion(&completion, &status, &actualByteCount);
IOStorage::complete(completion, status, actualByteCount);
deblocker->release();
return;
}
completion.target = driver;
completion.action = deblockRequestCompletion;
completion.parameter = deblocker;
context = (Context *) deblocker->getRequestContext();
driver->breakUpRequest(byteStart, deblocker, completion, context);
return;
}
class IOBreaker : public IOSubMemoryDescriptor
{
OSDeclareDefaultStructors(IOBreaker);
protected:
UInt64 _breakSize;
IOMemoryDescriptor * _requestBuffer;
IOStorageCompletion _requestCompletion;
void * _requestContext;
UInt64 _requestCount;
UInt64 _requestStart;
virtual void free();
public:
static IOBreaker * withBreakSize(
UInt64 breakSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext );
virtual bool initWithBreakSize(
UInt64 breakSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext );
virtual bool getNextStage(UInt64 * byteStart);
virtual void getRequestCompletion( IOStorageCompletion * completion,
IOReturn * status,
UInt64 * actualByteCount );
virtual IOMemoryDescriptor * getRequestBuffer();
virtual void * getRequestContext();
};
#undef super
#define super IOSubMemoryDescriptor
OSDefineMetaClassAndStructors(IOBreaker, IOSubMemoryDescriptor)
IOBreaker * IOBreaker::withBreakSize(
UInt64 breakSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext )
{
IOBreaker * me = new IOBreaker;
if ( me && me->initWithBreakSize(
breakSize,
withRequestStart,
withRequestBuffer,
withRequestCompletion,
withRequestContext ) == false )
{
me->release();
me = 0;
}
return me;
}
bool IOBreaker::initWithBreakSize(
UInt64 breakSize,
UInt64 withRequestStart,
IOMemoryDescriptor * withRequestBuffer,
IOStorageCompletion withRequestCompletion,
void * withRequestContext )
{
if ( super::initSubRange(
withRequestBuffer,
0,
withRequestBuffer->getLength(),
withRequestBuffer->getDirection() ) == false )
{
return false;
}
_breakSize = breakSize;
_length = 0;
_requestBuffer = withRequestBuffer;
_requestBuffer->retain();
_requestCompletion = withRequestCompletion;
_requestContext = withRequestContext;
_requestCount = withRequestBuffer->getLength();
_requestStart = withRequestStart;
return true;
}
void IOBreaker::free()
{
if ( _requestBuffer ) _requestBuffer->release();
super::free();
}
bool IOBreaker::getNextStage(UInt64 * byteStart)
{
if ( _start + _length < _requestCount )
{
_start += _length;
_length = min(_breakSize, _requestCount - _start);
}
else
{
return false;
}
*byteStart = _requestStart + _start;
return true;
}
void IOBreaker::getRequestCompletion( IOStorageCompletion * completion,
IOReturn * status,
UInt64 * actualByteCount )
{
*actualByteCount += _start;
*completion = _requestCompletion;
}
IOMemoryDescriptor * IOBreaker::getRequestBuffer()
{
return _requestBuffer;
}
void * IOBreaker::getRequestContext()
{
return _requestContext;
}
void IOBlockStorageDriver::breakUpRequest(
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageCompletion completion,
IOBlockStorageDriver::Context * context )
{
IOBreaker * breaker;
UInt64 breakSize;
assert((byteStart % context->block.size) == 0);
assert((buffer->getLength() % context->block.size) == 0);
if ( buffer->getDirection() == kIODirectionIn )
{
breakSize = min( _maxReadByteTransfer,
_maxReadBlockTransfer * context->block.size );
}
else
{
breakSize = min( _maxWriteByteTransfer,
_maxWriteBlockTransfer * context->block.size );
}
if ( buffer->getLength() <= breakSize )
{
executeRequest(byteStart, buffer, completion, context);
return;
}
breakSize = IOTrunc(breakSize, context->block.size);
breaker = IOBreaker::withBreakSize(
breakSize,
byteStart,
buffer,
completion,
context );
if ( breaker == 0 )
{
complete(completion, kIOReturnNoMemory);
return;
}
breakUpRequestCompletion(this, breaker, kIOReturnSuccess, 0);
return;
}
OSMetaClassDefineReservedUsed(IOBlockStorageDriver, 1);
void IOBlockStorageDriver::breakUpRequestCompletion( void * target,
void * parameter,
IOReturn status,
UInt64 actualByteCount )
{
UInt64 byteStart;
IOStorageCompletion completion;
Context * context;
IOBreaker * breaker = (IOBreaker *) parameter;
IOBlockStorageDriver * driver = (IOBlockStorageDriver *) target;
if ( actualByteCount < breaker->getLength() ||
status != kIOReturnSuccess ||
breaker->getNextStage(&byteStart) == false )
{
breaker->getRequestCompletion(&completion, &status, &actualByteCount);
IOStorage::complete(completion, status, actualByteCount);
breaker->release();
return;
}
completion.target = driver;
completion.action = breakUpRequestCompletion;
completion.parameter = breaker;
context = (Context *) breaker->getRequestContext();
driver->executeRequest(byteStart, breaker, completion, context);
return;
}
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 1);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 2);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 3);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 4);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 5);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 6);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 7);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 8);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 9);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 10);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 11);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 12);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 13);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 14);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 15);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 16);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 17);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 18);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 19);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 20);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 21);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 22);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 23);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 24);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 25);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 26);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 27);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 28);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 29);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 30);
OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 31);