Source to iokit/IOKit/storage/IODrive.h


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This 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 OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*!
 * @header IODrive
 * @abstract
 * This header contains the IODrive class definition.
 */

#ifndef _IODRIVE_H
#define _IODRIVE_H

/*!
 * @defined kIODriveStatistics
 * @abstract
 * kIODriveStatistics is a property of IODrive objects.  It is an OSDictionary.
 * @discussion
 * The kIODirectionStatistics property contains a table of statistics describing
 * drive operations.  All the different statistics are grouped under this table.
 */
 
#define kIODriveStatistics "Statistics"

/*!
 * @defined kIODriveStatisticsBytesRead
 * @abstract
 * kIODriveStatisticsBytesRead is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsBytesRead property describes the number of
 * bytes read since the drive object was instantiated.
 */

#define kIODriveStatisticsBytesRead "Bytes (Read)"

/*!
 * @defined kIODriveStatisticsBytesWritten
 * @abstract
 * kIODriveStatisticsBytesWritten is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsBytesWritten property describes the number of
 * bytes written since the drive object was instantiated.
 */

#define kIODriveStatisticsBytesWritten "Bytes (Write)"

/*!
 * @defined kIODriveStatisticsReadErrors
 * @abstract
 * kIODriveStatisticsReadErrors is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsReadErrors property describes the number of
 * read errors encountered since the drive object was instantiated.
 */

#define kIODriveStatisticsReadErrors "Errors (Read)"

/*!
 * @defined kIODriveStatisticsWriteErrors
 * @abstract
 * kIODriveStatisticsWriteErrors is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsWriteErrors property describes the number of
 * write errors encountered since the drive object was instantiated.
 */

#define kIODriveStatisticsWriteErrors "Errors (Write)"

/*!
 * @defined kIODriveStatisticsLatentReadTime
 * @abstract
 * kIODriveStatisticsLatentReadTime is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsLatentReadTime property describes the number of
 * nanoseconds of latency during reads since the drive object was instantiated.
 */

#define kIODriveStatisticsLatentReadTime "Latency Time (Read)"

/*!
 * @defined kIODriveStatisticsLatentWriteTime
 * @abstract
 * kIODriveStatisticsLatentWriteTime is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsLatentWriteTime property describes the number of
 * nanoseconds of latency during writes since the drive object was instantiated.
 */

#define kIODriveStatisticsLatentWriteTime "Latency Time (Write)"

/*!
 * @defined kIODriveStatisticsReads
 * @abstract
 * kIODriveStatisticsReads is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsReads property describes the number of
 * read operations processed since the drive object was instantiated.
 */

#define kIODriveStatisticsReads "Operations (Read)"

/*!
 * @defined kIODriveStatisticsWrites
 * @abstract
 * kIODriveStatisticsWrites is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsWrites property describes the number of
 * write operations processed since the drive object was instantiated.
 */

#define kIODriveStatisticsWrites "Operations (Write)"

/*!
 * @defined kIODriveStatisticsReadRetries
 * @abstract
 * kIODriveStatisticsReadRetries is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsReadRetries property describes the number of
 * read retries required since the drive object was instantiated.
 */

#define kIODriveStatisticsReadRetries "Retries (Read)"

/*!
 * @defined kIODriveStatisticsWriteRetries
 * @abstract
 * kIODriveStatisticsWriteRetries is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsWriteRetries property describes the number of
 * write retries required since the drive object was instantiated.
 */

#define kIODriveStatisticsWriteRetries "Retries (Write)"

/*!
 * @defined kIODriveStatisticsTotalReadTime
 * @abstract
 * kIODriveStatisticsTotalReadTime is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsTotalReadTime property describes the number of
 * nanoseconds spent performing reads since the drive object was instantiated.
 */

#define kIODriveStatisticsTotalReadTime "Total Time (Read)"

/*!
 * @defined kIODriveStatisticsTotalWriteTime
 * @abstract
 * kIODriveStatisticsTotalWriteTime is one of the statistic entries listed
 * under the kIODriveStatistics property of IODrive objects.  It is an OSNumber.
 * @discussion
 * The kIODriveStatisticsTotalWriteTime property describes the number of
 * nanoseconds spent performing writes since the drive object was instantiated.
 */

#define kIODriveStatisticsTotalWriteTime "Total Time (Write)"

/*
 * Kernel
 */

#if defined(KERNEL) && defined(__cplusplus)

#include <IOKit/storage/IOStorage.h>

/*!
 * @class IODrive
 * @abstract
 * The IODrive class is the common base class for all disk drive objects.
 * @discussion
 * The IODrive class is the common base class for all disk drive objects.  It
 * extends the IOStorage class by implementing the appropriate open and close
 * semantics for drive objects, deblocking for unaligned transfers, automatic
 * polling for removable media, statistics gathering and reporting functions,
 * and declaring the abstract APIs for media formatting, ejection and locking
 * (removal prevention).
 *
 * There are more specific subclasses of IODrive which further implement the
 * general semantics of hard disk drives (IOHDDrive), CD drives (IOCDDrive),
 * and so on.
 */

class IODrive : public IOStorage
{
    OSDeclareAbstractStructors(IODrive);

public:

    /*!
     * @enum Statistics
     * @discussion
     * Indices for the different statistics that getStatistics() can report.
     * @constant kStatisticsReads
     * Number of read operations thus far.
     * @constant kStatisticsSingleBlockReads
     * Number of read operations for a single block 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,
        kStatisticsSingleBlockReads,
        kStatisticsBytesRead,
        kStatisticsTotalReadTime,
        kStatisticsLatentReadTime,
        kStatisticsReadRetries,
        kStatisticsReadErrors,

        kStatisticsWrites,
        kStatisticsSingleBlockWrites,
        kStatisticsBytesWritten,
        kStatisticsTotalWriteTime,
        kStatisticsLatentWriteTime,
        kStatisticsWriteRetries,
        kStatisticsWriteErrors
    };

    static const UInt32 kStatisticsCount = kStatisticsWriteErrors + 1;

    /*!
     * @enum IOMediaState
     * @discussion
     * The different states that getMediaState() can report.
     * @constant kMediaOffline
     * Media is not available.
     * @constant kMediaOnline
     * Media is available and ready for operations.
     * @constant kMediaBusy
     * Media is available, but not ready for operations.
     */

    enum IOMediaState
    {
        kMediaOffline,
        kMediaOnline,
        kMediaBusy
    };

protected:

    OSSet *         _openClients;
    OSNumber *      _statistics[kStatisticsCount];

    /*
     * Free all of this object's outstanding resources.
     *
     * This method's implementation is not typically overidden.
     */

    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 kAccessReader or kAccessReaderWriter.
     * @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 specificed, 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 for this drive -- used for statistics.
     *
     * This method's implementation is not typically overidden.
     * @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 overidden.
     * @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 overidden.
     * @param isWrite
     * Indicates whether this operation was a write, otherwise is was a read.
     */

    virtual void incrementRetries(bool isWrite);

    /*!
     * @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 breaking up the request into sub-requests that rest on block
     * boundaries, and performing the appropriate unaligned byte copies from
     * the scratch buffer into into the client's request buffer.
     *
     * This method is part of a sequence of methods that are called for each
     * read or write request.  The first is deblockRequest, which aligns the
     * request at the media's block boundaries; the second is prepareRequest,
     * which prepares the memory involved in the transfer;  and the third is 
     * executeRequest, which implements the actual transfer from the drive.
     *
     * This method's implementation is not typically overidden.
     * @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 deblockRequest(UInt64               byteStart,
                                IOMemoryDescriptor * buffer,
                                IOStorageCompletion  completion);

    /*!
     * @function prepareRequest
     * @discussion
     * The prepareRequest method prepares the memory involved in the transfer.
     * The memory will be wired down, physically mapped, and broken up based
     * on the controller's and drive's constraints.
     *
     * This method is part of a sequence of methods that are called for each
     * read or write request.  The first is deblockRequest, which aligns the
     * request at the media's block boundaries; the second is prepareRequest,
     * which prepares the buffer involved in the transfer;  and the third is 
     * executeRequest, which implements the actual transfer from the drive.
     *
     * This method's implementation is not typically overidden.
     * @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 executeRequest
     * @discussion
     * Execute the specified storage request.  The request is guaranteed to
     * be block-aligned, and to have a memory buffer that is wired, mapped,
     * and is constrained according to the controller's and drive's limits.
     *
     * This method is part of a sequence of methods that are called for each
     * read or write request.  The first is deblockRequest, which aligns the
     * request at the media's block boundaries; the second is prepareRequest,
     * which prepares the buffer involved in the transfer;  and the third is 
     * executeRequest, which implements the actual transfer from the drive.
     *
     * When implementing this abstract method, it is important to remember
     * that the buffer must be retained while the asynchronous operation is
     * being processed, as per regular I/O Kit object-passing semantics.
     * @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 executeRequest(UInt64               byteStart,
                                IOMemoryDescriptor * buffer,
                                IOStorageCompletion  completion) = 0;

    /*!
     * @function handleStart
     * @discussion
     * Prepare the drive for operation.
     *
     * This is where a media object needs to be created for fixed media, and
     * optionally for removable media.  For removable media, the poller will
     * issue handlePoll() once a second, so the creation of the media object
     * could be delayed until then if you wish.
     *
     * Note that this method is called from the superclass' start() routine;
     * if this method returns successfully,  it should be prepared to accept
     * any of IODrive's abstract methods.
     * @param provider
     * This object's provider.
     * @result
     * Returns true on success, false otherwise.
     */

    virtual bool handleStart(IOService * provider) = 0;

    /*!
     * @function handleStop
     * @discussion
     * Stop the drive.
     *
     * This is where the driver should clean up its state in preparation for
     * removal from the system.
     *
     * Note that this method is called from the superclass' stop() routine.
     * @param provider
     * This object's provider.
     */

    virtual void handleStop(IOService * provider) = 0;

    /*!
     * @function getMediaBlockSize
     * @discussion
     * Ask the drive about the media's actual block size.
     * @result
     * Natural block size, in bytes.
     */

    virtual inline UInt64 getMediaBlockSize() const = 0;

public:

///m:2333367:workaround:commented:start
//  IOStorage::open;
//  IOStorage::close;
//  IOStorage::read;
//  IOStorage::write;
///m:2333367:workaround:commented:stop

    /*
     * Initialize this object's minimal state.
     *
     * This method's implementation is not typically overidden.
     */

    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 overidden.
     */

    virtual bool start(IOService * provider);

    /*
     * This method is called before we are detached from the provider object.
     *
     * This method's implementation is not typically overidden.
     */

    virtual void stop(IOService * provider);

    /*!
     * @function read
     * @discussion
     * The read method is the receiving end for all read requests from the
     * storage framework, that is, the child storage objects of this drive.
     *
     * This method kicks off a sequence of methods which are called for each
     * read or write request.  The first is deblockRequest, which aligns the
     * request at the media's block boundaries; the second is prepareRequest,
     * which prepares the buffer involved in the transfer;  and the third is 
     * executeRequest, which implements the actual transfer from the drive.
     *
     * This method's implementation is not typically overidden.
     * @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, that is, the child storage objects of this drive.
     *
     * This method kicks off a sequence of methods which are called for each
     * read or write request.  The first is deblockRequest, which aligns the
     * request at the media's block boundaries; the second is prepareRequest,
     * which prepares the buffer involved in the transfer;  and the third is 
     * executeRequest, which implements the actual transfer from the drive.
     *
     * This method's implementation is not typically overidden.
     * @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 ejectMedia
     * @discussion
     * Eject the media from the drive. The drive object is responsible for
     * tearing down the child storage objects it created before proceeding
     * with the eject.  If the teardown fails, an error should be returned.
     * @result
     * An IOReturn code.
     */

    virtual IOReturn ejectMedia() = 0;

    /*!
     * @function formatMedia
     * @discussion
     * Format the media in the drive with the specified byte capacity.    The
     * drive object is responsible for tearing down the child storage objects
     * and recreating them, if applicable.
     * @param byteCapacity
     * Number of bytes to format media to.
     * @result
     * An IOReturn code.
     */

    virtual IOReturn formatMedia(UInt64 byteCapacity) = 0;

    /*!
     * @function lockMedia
     * @discussion
     * Lock or unlock the ejectable media in the drive, 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) = 0;

    /*!
     * @function pollMedia
     * @discussion
     * Poll for the presence of media in the drive.  The drive object is
     * responsible for tearing down the child storage objects it created
     * should the media have been removed since the last poll, and vice-
     * versa,   creating the child storage objects should new media have
     * arrived since the last poll.
     * @result
     * An IOReturn code.
     */

    virtual IOReturn pollMedia() = 0;

    /*!
     * @function isMediaEjectable
     * @discussion
     * Ask the drive whether it contains ejectable media.
     * @result
     * Returns true if the media is ejectable, false otherwise.
     */

    virtual bool isMediaEjectable() const = 0;

    /*!
     * @function isMediaPollExpensive
     * @discussion
     * Ask the drive whether it a pollMedia would be an expensive operation,
     * that is, one that requires the drive to spin up or delay for a while.
     * @result
     * Returns true if polling the media is expensive, false otherwise.
     */

    virtual bool isMediaPollExpensive() const = 0;

    /*!
     * @function isMediaPollRequired
     * @discussion
     * Ask the drive whether it requires polling, which is typically required
     * for drives with ejectable media 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 = 0;

    /*!
     * @function getMediaState
     * @discussion
     * Ask the drive about the media's current state.
     * @result
     * An IOMediaState value.
     */

    virtual IOMediaState getMediaState() const = 0;

    /*!
     * @function getFormatCapacities
     * @discussion
     * Ask the drive 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 = 0;

    /*!
     * @function getStatistics
     * @discussion
     * Ask the drive to report its operating statistics.  The statistics are
     * described by the IODrive::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 drive to report one of its operating statistics.
     * @param statistic
     * Statistic index (an IODrive::Statistics index).
     * @result
     * Statistic value.
     */

    virtual UInt64 getStatistic(Statistics statistic) const;

protected:

    /*
     * Definitions for the default deblocker implementation.
     */

    enum DeblockerPhase
    {
        kPhaseBegin,
        kPhaseStart,
        kPhaseMiddle,
        kPhaseFinal,
        kPhaseDone,

        kPhaseBeginRMW,
        kPhaseStartRM,
        kPhaseStartW,
        kPhaseMiddleW,
        kPhaseFinalRM,
        kPhaseFinalW
    };

    struct DeblockerContext
    {
        struct
        {
            UInt64               byteStart;
            IOMemoryDescriptor * buffer;
            IOStorageCompletion  completion;
        } subrequest;

        UInt64               offsetStart;
        UInt64               bytesStart;
        UInt64               bytesMiddle;
        UInt64               bytesFinal;

        IOMemoryDescriptor * blockBuffer;
        UInt8 *              blockBufferPtr;

        IOMemoryDescriptor * middleBuffer;

        UInt64               bytesTransferred;

        struct
        {
            UInt64               byteStart;
            IOMemoryDescriptor * buffer;
            IOStorageCompletion  completion;
        } originalRequest;

        DeblockerPhase       phase;
    };

    IOLock * _deblockerLockForRMWs;

    /*
     * Allocate a deblocker context structure.  It comes preinitialized with
     * a block-sized scratch buffer and an associated memory descriptor, but
     * is otherwise uninitialized.
     */

    DeblockerContext * deblockerContextAllocate();

    /*
     * Deallocate a deblocker context structure.  The block-sized scratch
     * buffer and memory descriptor is automatically deallocated as well.
     */

    void deblockerContextFree(DeblockerContext * deblockContext);

    /*
     * This is the completion routine for the aligned deblocker subrequests.
     * It performs work on the just-completed phase, if any, transitions to
     * the next phase, then builds and issues a transfer for the next phase.
     */

    static void deblockerCompletion(void *   target,
                                    void *   parameter,
                                    IOReturn status,
                                    UInt64   actualByteCount);

    /*
     * Schedule the poller mechanism.
     */

    void schedulePoller();

    /*
     * Unschedule the poller mechanism.
     */

    void unschedulePoller();

    /*
     * This method is the timeout handler for the poller mechanism.  It polls
     * for media and reschedules another timeout if the drive is still closed.
     */

    static void poller(void *, void *);
};

#endif /* defined(KERNEL) && defined(__cplusplus) */

#endif /* !_IODRIVE_H */