IOBlockStorageDriver

Inherits from
IOStorage
Availability
Available in OS X v10.6 and later.
Declared in
IOBlockStorageDriver.h

Overview

The common base class for generic block storage drivers.

The IOBlockStorageDriver class is the common base class for generic block storage drivers. It matches and communicates via an IOBlockStorageDevice interface, and connects to the remainder of the storage framework via the IOStorage protocol. It extends the IOStorage protocol by implementing the appropriate open and close semantics, deblocking for unaligned transfers, polling for ejectable media, locking and ejection policies, media object creation and tear-down, and statistics gathering and reporting.

Block storage drivers are split into two parts: the generic driver handles all generic device issues, independent of the lower-level transport mechanism (e.g. SCSI, ATA, USB, FireWire). All storage operations at the generic driver level are translated into a series of generic device operations. These operations are passed via the IOBlockStorageDevice nub to a transport driver, which implements the appropriate transport-dependent protocol to execute these operations.

To determine the write-protect state of a device (or media), for example, the generic driver would issue a call to the Transport Driver's reportWriteProtection method. If this were a SCSI device, its transport driver would issue a Mode Sense command to extract the write-protection status bit. The transport driver then reports true or false to the generic driver.

The generic driver therefore has no knowledge of, or involvement with, the actual commands and mechanisms used to communicate with the device. It is expected that the generic driver will rarely, if ever, need to be subclassed to handle device idiosyncrasies; rather, the transport driver should be changed via overrides.

A generic driver could be subclassed to create a different type of generic device. The generic driver IOCDBlockStorageDriver class is a subclass of IOBlockStorageDriver, adding CD functions.

Tasks

Miscellaneous

Instance Methods

acceptNewMedia

React to new media insertion.

virtual IOReturn acceptNewMedia( void);
Discussion

This method logs the media block size and block count, then calls instantiateMediaObject to get a media object instantiated. The media object is then attached above us and registered.

This method can be overridden to control what happens when new media is inserted. The default implementation deals with one IOMedia object.

addToBytesTransferred

virtual void addToBytesTransferred( UInt64 bytesTransferred, UInt64 totalTime, UInt64 latentTime, bool isWrite);
Parameters
bytesTransferred

Number of bytes transferred in this operation.

totalTime

Nanoseconds spent performing this operation.

latentTime

Nanoseconds of latency during this operation.

isWrite

Indicates whether this operation was a write, otherwise is was a read.

Discussion

Update the total number of bytes transferred, the total transfer time, and the total latency time -- used for statistics.

This method's implementation is not typically overridden.

allocateContext

virtual Context * allocateContext();
Return Value

Context structure.

Discussion

Allocate a context structure for a read/write operation.

breakUpRequest

#ifdef __LP64__ virtual void breakUpRequest( UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageAttributes *attributes, IOStorageCompletion *completion, Context *context); #else /* !__LP64__ */ virtual void breakUpRequest( UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageCompletion completion, Context *context); #endif /* !__LP64__ */
Parameters
byteStart

Starting byte offset for the data transfer.

buffer

Buffer for the data transfer. The size of the buffer implies the size of the data transfer.

attributes

Attributes of the data transfer. See IOStorageAttributes. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

completion

Completion routine to call once the data transfer is complete. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

context

Additional context information for the data transfer (e.g. block size).

Discussion

The breakUpRequest method checks to see if the incoming request exceeds our transfer constraints, and if so, breaks up the request into smaller sub-requests.

This method is part of a sequence of methods invoked for each read/write request. The first is prepareRequest, which allocates and prepares some context for the transfer; the second is deblockRequest, which aligns the transfer at the media's block boundaries; third is breakUpRequest, which breaks up the transfer into multiple sub-transfers when certain hardware constraints are exceeded; fourth is executeRequest, which implements the actual transfer from the block storage device.

This method's implementation is not typically overridden.

checkForMedia

Check if media has newly arrived or disappeared.

virtual IOReturn checkForMedia( void);
Discussion

This method does most of the work in polling for media, first calling the block storage device's reportMediaState method. If reportMediaState reports no change in the media state, kIOReturnSuccess is returned. If the media state has indeed changed, a call is made to mediaStateHasChanged to act on the event.

constrainByteCount

Constrain the byte count for this IO to device limits.

virtual UInt64 constrainByteCount( UInt64 requestedCount, bool isWrite);
Parameters
requestedCount

The requested byte count for the next read or write operation.

isWrite

True if the operation will be a write; False if the operation will be a read.

Discussion

This function should be called prior to each read or write operation, so that the driver can constrain the requested byte count, as necessary, to meet current device limits. Such limits could be imposed by the device depending on operating modes, media types, or transport protocol (e.g. ATA, SCSI).

At present, this method is not used.

copyPhysicalExtent

virtual IOStorage * copyPhysicalExtent( IOService *client, UInt64 *byteStart, UInt64 *byteCount);
Parameters
client

Client requesting the operation.

byteStart

Starting byte offset for the operation. Returns a physical byte offset, relative to the physical storage object, on success.

byteCount

Size of the operation. Returns the actual number of bytes which can be transferred, relative to the physical storage object, on success.

Return Value

A reference to the physical storage object, which should be released by the caller, or a null on error.

Discussion

Convert the specified byte offset into a physical byte offset, relative to a physical storage object. This call should only be made within the context of lockPhysicalExtents().

deblockRequest

#ifdef __LP64__ virtual void deblockRequest( UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageAttributes *attributes, IOStorageCompletion *completion, Context *context); #else /* !__LP64__ */ virtual void deblockRequest( UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageCompletion completion, Context *context); #endif /* !__LP64__ */
Parameters
byteStart

Starting byte offset for the data transfer.

buffer

Buffer for the data transfer. The size of the buffer implies the size of the data transfer.

attributes

Attributes of the data transfer. See IOStorageAttributes. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

completion

Completion routine to call once the data transfer is complete. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

context

Additional context information for the data transfer (e.g. block size).

Discussion

The deblockRequest method checks to see if the incoming request rests on the media's block boundaries, and if not, deblocks it. Deblocking involves rounding out the request to the nearest block boundaries and transferring the excess bytes into a scratch buffer.

This method is part of a sequence of methods invoked for each read/write request. The first is prepareRequest, which allocates and prepares some context for the transfer; the second is deblockRequest, which aligns the transfer at the media's block boundaries; third is breakUpRequest, which breaks up the transfer into multiple sub-transfers when certain hardware constraints are exceeded; fourth is executeRequest, which implements the actual transfer from the block storage device.

This method's implementation is not typically overridden.

decommissionMedia

Decommission an existing piece of media that has gone away.

virtual IOReturn decommissionMedia( bool forcible);
Parameters
forcible

True to force forgetting of the media object even if terminate reports that there was an active client.

Discussion

This method wraps a call to terminate, to tear down the stack and the IOMedia object for the media. If "forcible" is true, the media object will be forgotten, and initMediaState will be called. A forcible decommission would occur when an unrecoverable error happens during tear-down (e.g. perhaps a client is still open), but we must still forget about the media.

deleteContext

virtual void deleteContext( Context *context);
Parameters
context

Context structure to be deleted.

Discussion

Delete a context structure from a read/write operation.

ejectMedia

virtual IOReturn ejectMedia();
Return Value

An IOReturn code.

Discussion

Eject the media from the device. The driver is responsible for tearing down the media object it created before proceeding with the eject. If the tear-down fails, an error should be returned.

executeRequest

#ifdef __LP64__ virtual void executeRequest( UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageAttributes *attributes, IOStorageCompletion *completion, Context *context); #else /* !__LP64__ */ virtual void executeRequest( UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageCompletion completion, Context *context); #endif /* !__LP64__ */
Parameters
byteStart

Starting byte offset for the data transfer.

buffer

Buffer for the data transfer. The size of the buffer implies the size of the data transfer.

attributes

Attributes of the data transfer. See IOStorageAttributes. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

completion

Completion routine to call once the data transfer is complete. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

context

Additional context information for the data transfer (e.g. block size).

Discussion

Execute an asynchronous storage request. The request is guaranteed to be block-aligned.

This method is part of a sequence of methods invoked for each read/write request. The first is prepareRequest, which allocates and prepares some context for the transfer; the second is deblockRequest, which aligns the transfer at the media's block boundaries; third is breakUpRequest, which breaks up the transfer into multiple sub-transfers when certain hardware constraints are exceeded; fourth is executeRequest, which implements the actual transfer from the block storage device.

formatMedia

virtual IOReturn formatMedia( UInt64 byteCapacity);
Parameters
byteCapacity

Number of bytes to format media to.

Return Value

An IOReturn code.

Discussion

Format the media with the specified byte capacity. The driver is responsible for tearing down the media object and recreating it.

getDeviceTypeName

Return the desired device name.

virtual const char * getDeviceTypeName( void);
Discussion

This method returns a string, used to compare the kIOBlockStorageDeviceTypeKey of our provider. This method is called from probe.

The default implementation of this method returns kIOBlockStorageDeviceTypeGeneric.

getFormatCapacities

virtual UInt32 getFormatCapacities( UInt64 *capacities, UInt32 capacitiesMaxCount) const;
Parameters
capacities

Buffer that will receive the UInt64 capacity values.

capacitiesMaxCount

Maximum number of capacity values that can be held in the buffer.

Return Value

Actual number of capacity values copied to the buffer, or if no buffer is given, the total number of capacity values available.

Discussion

Ask the driver to report the feasible formatting capacities for the inserted media (in bytes). This routine fills the caller's buffer, up to the maximum count specified if the real number of capacities would overflow the buffer. The return value indicates the actual number of capacities copied to the buffer.

If the capacities buffer is not supplied or if the maximum count is zero, the routine returns the proposed count of capacities instead.

getMediaBlockSize

virtual UInt64 getMediaBlockSize() const;
Return Value

Natural block size, in bytes.

Discussion

Ask the driver about the media's natural block size.

getMediaState

virtual IOMediaState getMediaState() const;
Return Value

An IOMediaState value.

Discussion

Ask the driver about the media's current state.

getStatistic

virtual UInt64 getStatistic( Statistics statistic) const;
Parameters
statistic

Statistic index (an IOBlockStorageDriver::Statistics index).

Return Value

Statistic value.

Discussion

Ask the driver to report one of its operating statistics.

getStatistics

virtual UInt32 getStatistics( UInt64 *statistics, UInt32 statisticsMaxCount) const;
Parameters
statistics

Buffer that will receive the UInt64 statistic values.

statisticsMaxCount

Maximum number of statistic values that can be held in the buffer.

Return Value

Actual number of statistic values copied to the buffer, or if no buffer is given, the total number of statistic values available.

Discussion

Ask the driver to report its operating statistics.

The statistics are each indexed by IOBlockStorageDriver::Statistics indices. This routine fills the caller's buffer, up to the maximum count specified if the real number of statistics would overflow the buffer. The return value indicates the actual number of statistics copied to the buffer.

If the statistics buffer is not supplied or if the maximum count is zero, the routine returns the proposed count of statistics instead.

handleClose

virtual void handleClose( IOService *client, IOOptionBits options);
Parameters
client

Client requesting the close.

options

Options for the close. Set to zero.

Discussion

The handleClose method closes the client's access to this object.

This implementation replaces the IOService definition of handleIsOpen().

handleIsOpen

virtual bool handleIsOpen( const IOService *client) const;
Parameters
client

Client to check the open state of. Set to zero to check the open state of all clients.

Return Value

Returns true if the client was (or clients were) open, false otherwise.

Discussion

The handleIsOpen method determines whether the specified client, or any client if none is specified, presently has an open on this object.

This implementation replaces the IOService definition of handleIsOpen().

handleOpen

virtual bool handleOpen( IOService *client, IOOptionBits options, void *access);
Parameters
client

Client requesting the open.

options

Options for the open. Set to zero.

access

Access level for the open. Set to kIOStorageAccessReader or kIOStorageAccessReaderWriter.

Return Value

Returns true if the open was successful, false otherwise.

Discussion

The handleOpen method grants or denies permission to access this object to an interested client. The argument is an IOStorageAccess value that specifies the level of access desired -- reader or reader-writer.

This method can be invoked to upgrade or downgrade the access level for an existing client as well. The previous access level will prevail for upgrades that fail, of course. A downgrade should never fail. If the new access level should be the same as the old for a given client, this method will do nothing and return success. In all cases, one, singular close-per-client is expected for all opens-per-client received.

This implementation replaces the IOService definition of handleIsOpen().

handleStart

virtual bool handleStart( IOService *provider);
Parameters
provider

This object's provider.

Return Value

Returns true on success, false otherwise.

Discussion

Prepare the block storage driver for operation.

This is where a media object needs to be created for fixed media, and optionally for removable media.

Note that this method is called from within the start() routine; if this method returns successfully, it should be prepared to accept any of IOBlockStorageDriver's APIs.

incrementErrors

virtual void incrementErrors( bool isWrite);
Parameters
isWrite

Indicates whether this operation was a write, otherwise is was a read.

Discussion

Update the total error count -- used for statistics.

This method's implementation is not typically overridden.

incrementRetries

virtual void incrementRetries( bool isWrite);
Parameters
isWrite

Indicates whether this operation was a write, otherwise is was a read.

Discussion

Update the total retry count -- used for statistics.

This method's implementation is not typically overridden.

initMediaState

Initialize media-related instance variables.

virtual void initMediaState( void);
Discussion

Called when media is not present, this method marks the device state as not having media present, not spun up, and write-enabled.

instantiateDesiredMediaObject

Create an IOMedia object for media.

virtual IOMedia * instantiateDesiredMediaObject( void);
Discussion

This method creates the exact type of IOMedia object desired. It is called by instantiateMediaObject. A subclass may override this one-line method to change the type of media object actually instantiated.

instantiateMediaObject

Create an IOMedia object for media.

virtual IOMedia * instantiateMediaObject( UInt64 base, UInt64 byteSize, UInt32 blockSize, char *mediaName);
Parameters
base

Byte number of beginning of active data area of the media. Usually zero.

byteSize

Size of the data area of the media, in bytes.

blockSize

Block size of the media, in bytes.

mediaName

Name of the IOMedia object.

Return Value

A pointer to the created IOMedia object, or a null on error.

Discussion

This method creates an IOMedia object from the supplied parameters. It is a convenience method to wrap the handful of steps to do the job.

isMediaEjectable

virtual bool isMediaEjectable() const;
Return Value

Returns true if the media is ejectable, false otherwise.

Discussion

Ask the driver whether the media is ejectable.

isMediaRemovable

virtual bool isMediaRemovable() const;
Return Value

Returns true if the media is ejectable, false otherwise.

Discussion

Ask the driver whether the media is ejectable.

isMediaWritable

virtual bool isMediaWritable() const;
Return Value

Returns true if the media is writable, false otherwise.

Discussion

Ask the driver whether the media is writable.

lockPhysicalExtents

virtual bool lockPhysicalExtents( IOService *client);
Parameters
client

Client requesting the operation.

Return Value

Returns true if the lock was successful, false otherwise.

Discussion

Lock the contents of the storage object against relocation temporarily, for the purpose of getting physical extents.

mediaStateHasChanged

React to a new media insertion or a media removal.

virtual IOReturn mediaStateHasChanged( IOMediaState state);
Discussion

This method is called on a media state change, that is, an arrival or removal. If media has just become available, calls are made to recordMediaParameters and acceptNewMedia. If media has just gone away, a call is made to decommissionMedia, with the forcible parameter set to true. The forcible tear-down is needed to enforce the disappearance of media, regardless of interested clients.

prepareRequest

virtual void prepareRequest( UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageAttributes *attributes, IOStorageCompletion *completion);
Parameters
byteStart

Starting byte offset for the data transfer.

buffer

Buffer for the data transfer. The size of the buffer implies the size of the data transfer.

attributes

Attributes of the data transfer. See IOStorageAttributes. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

completion

Completion routine to call once the data transfer is complete. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

Discussion

The prepareRequest method allocates and prepares state for the transfer.

This method is part of a sequence of methods invoked for each read/write request. The first is prepareRequest, which allocates and prepares some context for the transfer; the second is deblockRequest, which aligns the transfer at the media's block boundaries; third is breakUpRequest, which breaks up the transfer into multiple sub-transfers when certain hardware constraints are exceeded; fourth is executeRequest, which implements the actual transfer from the block storage device.

This method's implementation is not typically overridden.

read

virtual void read( IOService *client, UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageAttributes *attributes, IOStorageCompletion *completion);
Parameters
client

Client requesting the read.

byteStart

Starting byte offset for the data transfer.

buffer

Buffer for the data transfer. The size of the buffer implies the size of the data transfer.

attributes

Attributes of the data transfer. See IOStorageAttributes. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

completion

Completion routine to call once the data transfer is complete. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

Discussion

The read method is the receiving end for all read requests from the storage framework (through the media object created by this driver).

This method initiates a sequence of methods (stages) for each read/write request. The first is prepareRequest, which allocates and prepares some context for the transfer; the second is deblockRequest, which aligns the transfer at the media's block boundaries; third is breakUpRequest, which breaks up the transfer into multiple sub-transfers when certain hardware constraints are exceeded; fourth is executeRequest, which implements the actual transfer from the block storage device.

This method's implementation is not typically overridden.

recordMediaParameters

Obtain media-related parameters on media insertion.

virtual IOReturn recordMediaParameters( void);
Discussion

This method obtains media-related parameters via calls to the Transport Driver's reportBlockSize, reportMaxValidBlock, and reportWriteProtection methods.

rejectMedia

Reject new media.

virtual void rejectMedia( void);
Discussion

This method will be called if validateNewMedia returns False (thus rejecting the new media. A vendor may choose to override this method to control behavior when media is rejected.

The default implementation simply calls ejectMedia.

requestIdle

Request that the device enter an idle state.

virtual IOReturn requestIdle( void);
Discussion

Request that the device enter an idle state. The device will exit this state on the next read or write request, or as it sees necessary. One example is for a DVD drive to spin down when it enters such an idle state, and spin up on the next read request from the system.

synchronizeCache

virtual IOReturn synchronizeCache( IOService *client);
Parameters
client

Client requesting the cache synchronization.

Return Value

Returns the status of the cache synchronization.

Discussion

Flush the cached data in the storage object, if any, synchronously.

unlockPhysicalExtents

virtual void unlockPhysicalExtents( IOService *client);
Parameters
client

Client requesting the operation.

Discussion

Unlock the contents of the storage object for relocation again. This call must balance a successful call to lockPhysicalExtents().

unmap

virtual IOReturn unmap( IOService *client, IOStorageExtent *extents, UInt32 extentsCount, UInt32 options = 0);
Parameters
client

Client requesting the operation.

extents

List of extents. See IOStorageExtent. It is legal for the callee to overwrite the contents of this buffer in order to satisfy the request.

extentsCount

Number of extents.

Return Value

Returns the status of the operation.

Discussion

Delete unused data from the storage object at the specified byte offsets, synchronously.

validateNewMedia

Verify that new media is acceptable.

virtual bool validateNewMedia( void);
Discussion

This method will be called whenever new media is detected. Return true to accept the media, or false to reject it (and call rejectMedia). Vendors might override this method to handle password-protection for new media.

The default implementation always returns True, indicating media is accepted.

write

virtual void write( IOService *client, UInt64 byteStart, IOMemoryDescriptor *buffer, IOStorageAttributes *attributes, IOStorageCompletion *completion);
Parameters
client

Client requesting the write.

byteStart

Starting byte offset for the data transfer.

buffer

Buffer for the data transfer. The size of the buffer implies the size of the data transfer.

attributes

Attributes of the data transfer. See IOStorageAttributes. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

completion

Completion routine to call once the data transfer is complete. It is the responsibility of the callee to maintain the information for the duration of the data transfer, as necessary.

Discussion

The write method is the receiving end for all write requests from the storage framework (through the media object created by this driver).

This method initiates a sequence of methods (stages) for each read/write request. The first is prepareRequest, which allocates and prepares some context for the transfer; the second is deblockRequest, which aligns the transfer at the media's block boundaries; third is breakUpRequest, which breaks up the transfer into multiple sub-transfers when certain hardware constraints are exceeded; fourth is executeRequest, which implements the actual transfer from the block storage device.

This method's implementation is not typically overridden.

Constants

Statistics

Indices for the different statistics that getStatistics() can report.

enum Statistics {
   kStatisticsReads,
   kStatisticsBytesRead,
   kStatisticsTotalReadTime,
   kStatisticsLatentReadTime,
   kStatisticsReadRetries,
   kStatisticsReadErrors,
   kStatisticsWrites,
   kStatisticsSingleBlockWrites,
   kStatisticsBytesWritten,
   kStatisticsTotalWriteTime,
   kStatisticsLatentWriteTime,
   kStatisticsWriteRetries,
   kStatisticsWriteErrors
};
Constants
kStatisticsReads

Number of read operations thus far.

kStatisticsBytesRead

Number of bytes read thus far.

kStatisticsTotalReadTime

Nanoseconds spent performing reads thus far.

kStatisticsLatentReadTime

Nanoseconds of latency during reads thus far.

kStatisticsReadRetries

Number of read retries thus far.

kStatisticsReadErrors

Number of read errors thus far.

kStatisticsWrites

Number of write operations thus far.

kStatisticsSingleBlockWrites

Number of write operations for a single block thus far.

kStatisticsBytesWritten

Number of bytes written thus far.

kStatisticsTotalWriteTime

Nanoseconds spent performing writes thus far.

kStatisticsLatentWriteTime

Nanoseconds of latency during writes thus far.

kStatisticsWriteRetries

Number of write retries thus far.

kStatisticsWriteErrors

Number of write errors thus far.

Instance Variables

_ejectable

bool _ejectable;

True if the media is ejectable under software control.

_maxBlockNumber

UInt64 _maxBlockNumber;

The maximum allowable block number for the media, zero-based.

_maxReadByteTransfer

UInt64 _maxReadByteTransfer;

The maximum byte transfer allowed for read operations.

_maxWriteByteTransfer

UInt64 _maxWriteByteTransfer;

The maximum byte transfer allowed for write operations.

_mediaBlockSize

UInt64 _mediaBlockSize;

The block size of the media, in bytes.

_mediaObject

IOMedia * _mediaObject;

A pointer to the media object we have instantiated (if any).

_mediaType

UInt32 _mediaType;

Type of the media (can be used to differentiate between the different types of CD media, DVD media, etc).

_removable

bool _removable;

True if the media is removable; False if it is fixed (not removable).

_writeProtected

bool _writeProtected;

True if the media is write-protected; False if not.