/* * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * 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@ */ /*! * @header IOBlockStorageDriver * @abstract * This header contains the IOBlockStorageDriver class definition. */ #ifndef _IOBLOCKSTORAGEDRIVER_H #define _IOBLOCKSTORAGEDRIVER_H #include /*! * @defined kIOBlockStorageDriverClass * @abstract * The name of the IOBlockStorageDriver class. */ #define kIOBlockStorageDriverClass "IOBlockStorageDriver" /*! * @defined kIOBlockStorageDriverStatisticsKey * @abstract * Holds a table of numeric values describing the driver's * operating statistics. * @discussion * This property holds a table of numeric values describing the driver's * operating statistics. The table is an OSDictionary, where each entry * describes one given statistic. */ #define kIOBlockStorageDriverStatisticsKey "Statistics" /*! * @defined kIOBlockStorageDriverStatisticsBytesReadKey * @abstract * Describes the number of bytes read since the block storage * driver was instantiated. * @discussion * This property describes the number of bytes read since the block storage * driver was instantiated. It is one of the statistic entries listed under * the top-level kIOBlockStorageDriverStatisticsKey property table. It has * an OSNumber value. */ #define kIOBlockStorageDriverStatisticsBytesReadKey "Bytes (Read)" /*! * @defined kIOBlockStorageDriverStatisticsBytesWrittenKey * @abstract * Describes the number of bytes written since the block storage * driver was instantiated. * @discussion * This property describes the number of bytes written since the block storage * driver was instantiated. It is one of the statistic entries listed under the * top-level kIOBlockStorageDriverStatisticsKey property table. It has an * OSNumber value. */ #define kIOBlockStorageDriverStatisticsBytesWrittenKey "Bytes (Write)" /*! * @defined kIOBlockStorageDriverStatisticsReadErrorsKey * @abstract * Describes the number of read errors encountered since the block * storage driver was instantiated. * @discussion * This property describes the number of read errors encountered since the block * storage driver was instantiated. It is one of the statistic entries listed * under the top-level kIOBlockStorageDriverStatisticsKey property table. It * has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsReadErrorsKey "Errors (Read)" /*! * @defined kIOBlockStorageDriverStatisticsWriteErrorsKey * @abstract * Describes the number of write errors encountered since the * block storage driver was instantiated. * @discussion * This property describes the number of write errors encountered since the * block storage driver was instantiated. It is one of the statistic entries * listed under the top-level kIOBlockStorageDriverStatisticsKey property table. * It has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsWriteErrorsKey "Errors (Write)" /*! * @defined kIOBlockStorageDriverStatisticsLatentReadTimeKey * @abstract * Describes the number of nanoseconds of latency during reads * since the block storage driver was instantiated. * @discussion * This property describes the number of nanoseconds of latency during reads * since the block storage driver was instantiated. It is one of the statistic * entries listed under the top-level kIOBlockStorageDriverStatisticsKey * property table. It has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsLatentReadTimeKey "Latency Time (Read)" /*! * @defined kIOBlockStorageDriverStatisticsLatentWriteTimeKey * @abstract * Describes the number of nanoseconds of latency during writes * since the block storage driver was instantiated. * @discussion * This property describes the number of nanoseconds of latency during writes * since the block storage driver was instantiated. It is one of the statistic * entries listed under the top-level kIOBlockStorageDriverStatisticsKey * property table. It has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsLatentWriteTimeKey "Latency Time (Write)" /*! * @defined kIOBlockStorageDriverStatisticsReadsKey * @abstract * Describes the number of read operations processed since the * block storage driver was instantiated. * @discussion * This property describes the number of read operations processed since the * block storage driver was instantiated. It is one of the statistic entries * listed under the top-level kIOBlockStorageDriverStatisticsKey property table. * It has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsReadsKey "Operations (Read)" /*! * @defined kIOBlockStorageDriverStatisticsWritesKey * @abstract * Describes the number of write operations processed since the * block storage driver was instantiated. * @discussion * This property describes the number of write operations processed since the * block storage driver was instantiated. It is one of the statistic entries * listed under the top-level kIOBlockStorageDriverStatisticsKey property table. * It has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsWritesKey "Operations (Write)" /*! * @defined kIOBlockStorageDriverStatisticsReadRetriesKey * @abstract * Describes the number of read retries required since the block * storage driver was instantiated. * @discussion * This property describes the number of read retries required since the block * storage driver was instantiated. It is one of the statistic entries listed * under the top-level kIOBlockStorageDriverStatisticsKey property table. It * has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsReadRetriesKey "Retries (Read)" /*! * @defined kIOBlockStorageDriverStatisticsWriteRetriesKey * @abstract * Describes the number of write retries required since the block * storage driver was instantiated. * @discussion * This property describes the number of write retries required since the block * storage driver was instantiated. It is one of the statistic entries listed * under the top-level kIOBlockStorageDriverStatisticsKey property table. It * has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsWriteRetriesKey "Retries (Write)" /*! * @defined kIOBlockStorageDriverStatisticsTotalReadTimeKey * @abstract * Describes the number of nanoseconds spent performing reads * since the block storage driver was instantiated. * @discussion * This property describes the number of nanoseconds spent performing reads * since the block storage driver was instantiated. It is one of the statistic * entries listed under the top-level kIOBlockStorageDriverStatisticsKey * property table. It has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsTotalReadTimeKey "Total Time (Read)" /*! * @defined kIOBlockStorageDriverStatisticsTotalWriteTimeKey * @abstract * Describes the number of nanoseconds spent performing writes * since the block storage driver was instantiated. * @discussion * This property describes the number of nanoseconds spent performing writes * since the block storage driver was instantiated. It is one of the statistic * entries listed under the top-level kIOBlockStorageDriverStatisticsKey * property table. It has an OSNumber value. */ #define kIOBlockStorageDriverStatisticsTotalWriteTimeKey "Total Time (Write)" /*! * @enum IOMediaState * @abstract * The different states that getMediaState() can report. * @constant kIOMediaStateOffline * Media is not available. * @constant kIOMediaStateOnline * Media is available and ready for operations. * @constant kIOMediaStateBusy * Media is available, but not ready for operations. */ typedef UInt32 IOMediaState; #define kIOMediaStateOffline 0 #define kIOMediaStateOnline 1 #define kIOMediaStateBusy 2 #ifdef KERNEL #ifdef __cplusplus /* * Kernel */ #include #include #include #include /*! * @class IOBlockStorageDriver * @abstract * The common base class for generic block storage drivers. * @discussion * 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. */ class IOBlockStorageDriver : public IOStorage { OSDeclareDefaultStructors(IOBlockStorageDriver); public: /*! * @enum Statistics * @abstract * Indices for the different statistics that getStatistics() can report. * @constant kStatisticsReads Number of read operations thus far. * @constant kStatisticsBytesRead Number of bytes read thus far. * @constant kStatisticsTotalReadTime Nanoseconds spent performing reads thus far. * @constant kStatisticsLatentReadTime Nanoseconds of latency during reads thus far. * @constant kStatisticsReadRetries Number of read retries thus far. * @constant kStatisticsReadErrors Number of read errors thus far. * @constant kStatisticsWrites Number of write operations thus far. * @constant kStatisticsSingleBlockWrites Number of write operations for a single block thus far. * @constant kStatisticsBytesWritten Number of bytes written thus far. * @constant kStatisticsTotalWriteTime Nanoseconds spent performing writes thus far. * @constant kStatisticsLatentWriteTime Nanoseconds of latency during writes thus far. * @constant kStatisticsWriteRetries Number of write retries thus far. * @constant kStatisticsWriteErrors Number of write errors thus far. */ enum Statistics { kStatisticsReads, kStatisticsBytesRead, kStatisticsTotalReadTime, kStatisticsLatentReadTime, kStatisticsReadRetries, kStatisticsReadErrors, kStatisticsWrites, kStatisticsSingleBlockWrites, kStatisticsBytesWritten, kStatisticsTotalWriteTime, kStatisticsLatentWriteTime, kStatisticsWriteRetries, kStatisticsWriteErrors }; static const UInt32 kStatisticsCount = kStatisticsWriteErrors + 1; protected: struct ExpansionData { bool mediaDirtied; UInt64 maxReadBlockTransfer; UInt64 maxWriteBlockTransfer; IONotifier * powerEventNotifier; UInt32 deblockRequestWriteLockCount; UInt64 maxReadSegmentTransfer; UInt64 maxWriteSegmentTransfer; UInt64 maxReadSegmentByteTransfer; UInt64 maxWriteSegmentByteTransfer; }; ExpansionData * _expansionData; #define _mediaDirtied \ IOBlockStorageDriver::_expansionData->mediaDirtied #define _maxReadBlockTransfer \ IOBlockStorageDriver::_expansionData->maxReadBlockTransfer #define _maxWriteBlockTransfer \ IOBlockStorageDriver::_expansionData->maxWriteBlockTransfer #define _powerEventNotifier \ IOBlockStorageDriver::_expansionData->powerEventNotifier #define _deblockRequestWriteLockCount \ IOBlockStorageDriver::_expansionData->deblockRequestWriteLockCount #define _maxReadSegmentTransfer \ IOBlockStorageDriver::_expansionData->maxReadSegmentTransfer #define _maxWriteSegmentTransfer \ IOBlockStorageDriver::_expansionData->maxWriteSegmentTransfer #define _maxReadSegmentByteTransfer \ IOBlockStorageDriver::_expansionData->maxReadSegmentByteTransfer #define _maxWriteSegmentByteTransfer \ IOBlockStorageDriver::_expansionData->maxWriteSegmentByteTransfer OSSet * _openClients; OSNumber * _statistics[kStatisticsCount]; /* * @struct Context * @discussion * Context structure for a read/write operation. It describes the block size, * and where applicable, a block type and block sub-type, for a data transfer, * as well as the completion information for the original request. Note that * the block type field is unused in the IOBlockStorageDriver class. * @field block.size * Block size for the operation. * @field block.type * Block type for the operation. Unused in IOBlockStorageDriver. The default * value for this field is IOBlockStorageDriver::kBlockTypeStandard. * @field block.typeSub * Block sub-type for the operation. It's definition depends on block.type. * Unused in IOBlockStorageDriver. * @field original.byteStart * Starting byte offset for the data transfer. * @param original.buffer * Buffer for the data transfer. The size of the buffer implies the size of * the data transfer. * @param original.completion * Completion routine to call once the data transfer is complete. */ struct Context { struct { UInt32 size; UInt8 type; UInt8 typeSub[3]; } block; struct { UInt64 byteStart; IOMemoryDescriptor * buffer; IOStorageCompletion completion; } original; UInt32 reserved[8]; }; static const UInt8 kBlockTypeStandard = 0x00; /* * Free all of this object's outstanding resources. * * This method's implementation is not typically overridden. */ void free(); /*! * @function handleOpen * @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(). * @param client * Client requesting the open. * @param options * Options for the open. Set to zero. * @param access * Access level for the open. Set to kIOStorageAccessReader or * kIOStorageAccessReaderWriter. * @result * Returns true if the open was successful, false otherwise. */ virtual bool handleOpen(IOService * client, IOOptionBits options, void * access); /*! * @function handleIsOpen * @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(). * @param client * Client to check the open state of. Set to zero to check the open state * of all clients. * @result * Returns true if the client was (or clients were) open, false otherwise. */ virtual bool handleIsOpen(const IOService * client) const; /*! * @function handleClose * @discussion * The handleClose method closes the client's access to this object. * * This implementation replaces the IOService definition of handleIsOpen(). * @param client * Client requesting the close. * @param options * Options for the close. Set to zero. */ virtual void handleClose(IOService * client, IOOptionBits options); /*! * @function addToBytesTransferred * @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. * @param bytesTransferred * Number of bytes transferred in this operation. * @param totalTime * Nanoseconds spent performing this operation. * @param latentTime * Nanoseconds of latency during this operation. * @param isWrite * Indicates whether this operation was a write, otherwise is was a read. */ virtual void addToBytesTransferred(UInt64 bytesTransferred, UInt64 totalTime, UInt64 latentTime, bool isWrite); /*! * @function incrementErrors * @discussion * Update the total error count -- used for statistics. * * This method's implementation is not typically overridden. * @param isWrite * Indicates whether this operation was a write, otherwise is was a read. */ virtual void incrementErrors(bool isWrite); /*! * @function incrementRetries * @discussion * Update the total retry count -- used for statistics. * * This method's implementation is not typically overridden. * @param isWrite * Indicates whether this operation was a write, otherwise is was a read. */ virtual void incrementRetries(bool isWrite); /*! * @function allocateContext * @discussion * Allocate a context structure for a read/write operation. * @result * Context structure. */ virtual Context * allocateContext(); /*! * @function deleteContext * @discussion * Delete a context structure from a read/write operation. * @param context * Context structure to be deleted. */ virtual void deleteContext(Context * context); /*! * @function prepareRequest * @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. * @param byteStart * Starting byte offset for the data transfer. * @param buffer * Buffer for the data transfer. The size of the buffer implies the size of * the data transfer. * @param completion * Completion routine to call once the data transfer is complete. */ virtual void prepareRequest(UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion); /*! * @function deblockRequest * @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. * @param byteStart * Starting byte offset for the data transfer. * @param buffer * Buffer for the data transfer. The size of the buffer implies the size of * the data transfer. * @param completion * Completion routine to call once the data transfer is complete. * @param context * Additional context information for the data transfer (e.g. block size). */ virtual void deblockRequest(UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion, Context * context); /*! * @function executeRequest * @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. * @param byteStart * Starting byte offset for the data transfer. * @param buffer * Buffer for the data transfer. The size of the buffer implies the size of * the data transfer. * @param completion * Completion routine to call once the data transfer is complete. * @param context * Additional context information for the data transfer (e.g. block size). */ virtual void executeRequest(UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion, Context * context); /*! * @function handleStart * @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. * @param provider * This object's provider. * @result * Returns true on success, false otherwise. */ virtual bool handleStart(IOService * provider); /*! * @function handleYield * @discussion * Stop the block storage driver. * * This method is called as a result of a kIOMessageServiceIsRequestingClose * provider message. The argument is passed in as-is from the message. The * options are unused. * * This is where the driver should clean up its state in preparation for * removal from the system. * * Note that this method is called from within the yield() routine. * * This method is called with the arbitration lock held. * @param provider * This object's provider. */ virtual bool handleYield(IOService * provider, IOOptionBits options = 0, void * argument = 0); /*! * @function getMediaBlockSize * @discussion * Ask the driver about the media's natural block size. * @result * Natural block size, in bytes. */ virtual UInt64 getMediaBlockSize() const; public: using IOStorage::read; using IOStorage::write; /* * Initialize this object's minimal state. * * This method's implementation is not typically overridden. */ virtual bool init(OSDictionary * properties = 0); /* * This method is called once we have been attached to the provider object. * * This method's implementation is not typically overridden. */ virtual bool start(IOService * provider); /* * This method is called before we are detached from the provider object. * * This method's implementation is not typically overridden. */ virtual void stop(IOService * provider); /* * This method is called as a result of a kIOMessageServiceIsRequestingClose * provider message. The argument is passed in as-is from the message. The * options are unused. * * This method's implementation is not typically overridden. */ virtual bool yield(IOService * provider, IOOptionBits options = 0, void * argument = 0); /*! * @function read * @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. * @param client * Client requesting the read. * @param byteStart * Starting byte offset for the data transfer. * @param buffer * Buffer for the data transfer. The size of the buffer implies the size of * the data transfer. * @param completion * Completion routine to call once the data transfer is complete. */ virtual void read(IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion); /*! * @function write * @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. * @param client * Client requesting the write. * @param byteStart * Starting byte offset for the data transfer. * @param buffer * Buffer for the data transfer. The size of the buffer implies the size of * the data transfer. * @param completion * Completion routine to call once the data transfer is complete. */ virtual void write(IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion); /*! * @function synchronizeCache * @discussion * Flush the cached data in the storage object, if any, synchronously. * @param client * Client requesting the cache synchronization. * @result * Returns the status of the cache synchronization. */ virtual IOReturn synchronizeCache(IOService * client); /*! * @function ejectMedia * @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. * @result * An IOReturn code. */ virtual IOReturn ejectMedia(); /*! * @function formatMedia * @discussion * Format the media with the specified byte capacity. The driver is * responsible for tearing down the media object and recreating it. * @param byteCapacity * Number of bytes to format media to. * @result * An IOReturn code. */ virtual IOReturn formatMedia(UInt64 byteCapacity); /*! * @function lockMedia * @discussion * Lock or unlock the ejectable media in the device, that is, prevent * it from manual ejection or allow its manual ejection. * @param lock * Pass true to lock the media, otherwise pass false to unlock the media. * @result * An IOReturn code. */ virtual IOReturn lockMedia(bool lock); /*! * @function pollMedia * @discussion * Poll for the presence of media in the device. The driver is responsible * for tearing down the media object it created should the media have been * removed since the last poll, and vice-versa, creating the media object * should new media have arrived since the last poll. * @result * An IOReturn code. */ virtual IOReturn pollMedia(); /*! * @function isMediaEjectable * @discussion * Ask the driver whether the media is ejectable. * @result * Returns true if the media is ejectable, false otherwise. */ virtual bool isMediaEjectable() const; /*! * @function isMediaPollExpensive * @discussion * Ask the driver whether a pollMedia() would be an expensive operation, * that is, one that requires the device to spin up or delay for a while. * @result * Returns true if polling the media is expensive, false otherwise. */ virtual bool isMediaPollExpensive() const; /*! * @function isMediaPollRequired * @discussion * Ask the driver whether the block storage device requires polling, which is * typically required for devices without the ability to asynchronously detect * the arrival or departure of the media. * @result * Returns true if polling the media is required, false otherwise. */ virtual bool isMediaPollRequired() const; virtual bool isMediaWritable() const; /*! * @function getMediaState * @discussion * Ask the driver about the media's current state. * @result * An IOMediaState value. */ virtual IOMediaState getMediaState() const; /*! * @function getFormatCapacities * @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. * @param capacities * Buffer that will receive the UInt64 capacity values. * @param capacitiesMaxCount * Maximum number of capacity values that can be held in the buffer. * @result * Actual number of capacity values copied to the buffer, or if no buffer * is given, the total number of capacity values available. */ virtual UInt32 getFormatCapacities(UInt64 * capacities, UInt32 capacitiesMaxCount) const; /*! * @function getStatistics * @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. * @param statistics * Buffer that will receive the UInt64 statistic values. * @param statisticsMaxCount * Maximum number of statistic values that can be held in the buffer. * @result * Actual number of statistic values copied to the buffer, or if no buffer * is given, the total number of statistic values available. */ virtual UInt32 getStatistics(UInt64 * statistics, UInt32 statisticsMaxCount) const; /*! * @function getStatistic * @discussion * Ask the driver to report one of its operating statistics. * @param statistic * Statistic index (an IOBlockStorageDriver::Statistics index). * @result * Statistic value. */ virtual UInt64 getStatistic(Statistics statistic) const; /* * Generic entry point for calls from the provider. A return value of * kIOReturnSuccess indicates that the message was received, and where * applicable, that it was successful. */ virtual IOReturn message(UInt32 type, IOService * provider, void * argument); /* * Obtain this object's provider. We override the superclass's method to * return a more specific subclass of IOService -- IOBlockStorageDevice. * This method serves simply as a convenience to subclass developers. */ virtual IOBlockStorageDevice * getProvider() const; protected: IOLock * _deblockRequestWriteLock; thread_call_t _pollerCall; /* * This is the completion routine for the broken up breaker sub-requests. * It verifies the success of the just-completed stage, transitions to * the next stage, then builds and issues a transfer for the next stage. */ static void breakUpRequestCompletion(void * target, void * parameter, IOReturn status, UInt64 actualByteCount); /* * This is the completion routine for the aligned deblocker sub-requests. * It verifies the success of the just-completed stage, transitions to * the next stage, then builds and issues a transfer for the next stage. */ static void deblockRequestCompletion(void * target, void * parameter, IOReturn status, UInt64 actualByteCount); /* * This is the completion routine for the prepared request. It updates * the driver's statistics, performs some clean up work, then calls the * original request's completion routine. */ static void prepareRequestCompletion(void * target, void * parameter, IOReturn status, UInt64 actualByteCount); /* * Schedule the poller mechanism. */ virtual void schedulePoller(); /* * Unschedule the poller mechanism. */ virtual void unschedulePoller(); /* * This method is the timeout handler for the poller mechanism. It polls * for media and reschedules another timeout if there are still no opens. */ static void poller(void *, void *); /* * This method is the power event handler for restarts and shutdowns. */ static IOReturn handlePowerEvent(void * target, void * parameter, UInt32 messageType, IOService * provider, void * messageArgument, vm_size_t messageArgumentSize); protected: /* Device info: */ /*! * @var _removable * True if the media is removable; False if it is fixed (not removable). */ bool _removable; /*! * @var _ejectable * True if the media is ejectable under software control. */ bool _ejectable; /* software-ejectable */ /*! * @var _lockable * True if the media can be locked in the device under software control. */ bool _lockable; /* software lockable in device */ /*! * @var _pollIsRequired * True if we must poll to detect media insertion or removal. */ bool _pollIsRequired; /*! * @var _pollIsExpensive * True if polling is expensive; False if not. */ bool _pollIsExpensive; /* Media info and states: */ /*! * @var _mediaObject * A pointer to the media object we have instantiated (if any). */ IOMedia * _mediaObject; /*! * @var _mediaType * Type of the media (can be used to differentiate between the * different types of CD media, DVD media, etc). */ UInt32 _mediaType; /*! * @var _mediaPresent * True if media is present in the device; False if not. */ bool _mediaPresent; /* media is present and ready */ /*! * @var _writeProtected * True if the media is write-protected; False if not. */ bool _writeProtected; private: /*! * @var _mediaStateLock * A lock used to protect during media checks. */ IOLock * _mediaStateLock; protected: /*! * @var _mediaBlockSize * The block size of the media, in bytes. */ UInt64 _mediaBlockSize; /*! * @var _maxBlockNumber * The maximum allowable block number for the media, zero-based. */ UInt64 _maxBlockNumber; /*! * @var _maxReadByteTransfer * The maximum byte transfer allowed for read operations. */ UInt64 _maxReadByteTransfer; /*! * @var _maxWriteByteTransfer * The maximum byte transfer allowed for write operations. */ UInt64 _maxWriteByteTransfer; /*! * @function acceptNewMedia * @abstract * React to new media insertion. * @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. */ virtual IOReturn acceptNewMedia(void); /*! * @function constrainByteCount * @abstract * Constrain the byte count for this IO to device limits. * @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. * @param requestedCount * The requested byte count for the next read or write operation. * @param isWrite * True if the operation will be a write; False if the operation will be a read. */ virtual UInt64 constrainByteCount(UInt64 requestedCount,bool isWrite); /*! * @function decommissionMedia * @abstract * Decommission an existing piece of media that has gone away. * @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. * @param forcible * True to force forgetting of the media object even if terminate reports * that there was an active client. */ virtual IOReturn decommissionMedia(bool forcible); /*! * @function instantiateDesiredMediaObject * @abstract * Create an IOMedia object for media. * @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. */ virtual IOMedia * instantiateDesiredMediaObject(void); /*! * @function instantiateMediaObject * @abstract * Create an IOMedia object for media. * @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. * @param base * Byte number of beginning of active data area of the media. Usually zero. * @param byteSize * Size of the data area of the media, in bytes. * @param blockSize * Block size of the media, in bytes. * @param mediaName * Name of the IOMedia object. * @result * A pointer to the created IOMedia object, or a null on error. */ virtual IOMedia * instantiateMediaObject(UInt64 base,UInt64 byteSize, UInt32 blockSize,char *mediaName); /*! * @function recordMediaParameters * @abstract * Obtain media-related parameters on media insertion. * @discussion * This method obtains media-related parameters via calls to the * Transport Driver's reportBlockSize, reportMaxValidBlock, * reportMaxReadTransfer, reportMaxWriteTransfer, and reportWriteProtection * methods. */ virtual IOReturn recordMediaParameters(void); /*! * @function rejectMedia * @abstract * Reject new media. * @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. */ virtual void rejectMedia(void); /* default ejects */ /*! * @function validateNewMedia * @abstract * Verify that new media is acceptable. * @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. */ virtual bool validateNewMedia(void); /* --- Internally used methods. --- */ /* * @group * Internally Used Methods * @discussion * These methods are used internally, and will not generally be modified. */ /*! * @function checkForMedia * @abstract * Check if media has newly arrived or disappeared. * @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. */ virtual IOReturn checkForMedia(void); /*! * @function getDeviceTypeName * @abstract * Return the desired device name. * @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. */ virtual const char * getDeviceTypeName(void); /*! * @function initMediaState * @abstract * Initialize media-related instance variables. * @discussion * Called when media is not present, this method marks the device state * as not having media present, not spun up, and write-enabled. */ virtual void initMediaState(void); /*! * @function mediaStateHasChanged * @abstract * React to a new media insertion or a media removal. * @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. */ virtual IOReturn mediaStateHasChanged(IOMediaState state); /* * @endgroup */ protected: /*! * @function breakUpRequest * @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. * @param byteStart * Starting byte offset for the data transfer. * @param buffer * Buffer for the data transfer. The size of the buffer implies the size of * the data transfer. * @param completion * Completion routine to call once the data transfer is complete. * @param context * Additional context information for the data transfer (e.g. block size). */ virtual void breakUpRequest(UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion, Context * context); OSMetaClassDeclareReservedUsed(IOBlockStorageDriver, 0); /* 10.1.2 */ OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 1); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 2); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 3); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 4); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 5); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 6); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 7); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 8); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 9); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 10); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 11); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 12); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 13); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 14); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 15); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 16); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 17); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 18); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 19); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 20); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 21); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 22); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 23); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 24); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 25); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 26); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 27); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 28); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 29); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 30); OSMetaClassDeclareReservedUnused(IOBlockStorageDriver, 31); }; #endif /* __cplusplus */ #endif /* KERNEL */ #endif /* !_IOBLOCKSTORAGEDRIVER_H */