Source to iokit/IOKit/storage/IOHDDrive.h
/*
* 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@
*/
/* =============================================================================
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* IOHDDrive.h
*
* This class implements generic Hard Disk functionality, independent of
* the physical connection protocol (e.g. SCSI, ATA, USB).
*
* A protocol-specific provider implements the functionality using an appropriate
* protocol and commands.
*/
#ifndef _IOHDDRIVE_H
#define _IOHDDRIVE_H
#include <IOKit/IOTypes.h>
#include <IOKit/storage/IOStorage.h>
#include <IOKit/storage/IODrive.h>
#include <IOKit/IOMemoryDescriptor.h>
class IOHDDriveNub;
class IOMedia;
/*!
* @class
* IOHDDrive : public IODrive
* @abstract
* Generic Hard Disk Driver.
* @discussion
* 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 Device 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 IOCDDrive class is a subclass
* of IOHDDrive, adding CD functions. Similarly, the Transport Driver
* IOSCSICDDrive is a subclass of IOSCSIHDDrive, adding CD functions.
*/
class IOHDDrive : public IODrive {
OSDeclareDefaultStructors(IOHDDrive)
public:
struct context {
IOStorageCompletion completion;
IOMemoryDescriptor * buffer;
UInt64 byteStart;
UInt64 byteCount;
IOReturn result;
UInt64 actualTransferCount;
};
/* Overrides from IORegistryEntry */
virtual void free(void);
virtual bool init(OSDictionary * properties);
/* Overrides from IOService */
/*!
* @function probe
* @abstract
* Probe for proper client Transport Driver.
* @discussion
* This method first verifies that our provider is of class IOHDDriveNub, then
* checks that the provider's property "kDeviceTypeProperty" matches what we expect.
* Failure of either test causes a return of NULL.
*/
virtual IOService * probe(IOService * provider,SInt32 * score);
/* Mandatory overrides from IODrive: */
/*!
* @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 prototol (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 ejectMedia
* @abstract
* Eject the media.
*/
virtual IOReturn ejectMedia(void);
/*!
* @function formatMedia
* @abstract
* Format the media to the specified byte capacity.
* @param byteCapacity
* The requested final byte capacity for the formatted media.
*/
virtual IOReturn formatMedia(UInt64 byteCapacity);
/*!
* @function getFormatCapacities
* @abstract
* Return the allowable formatting byte capacities.
* @discussion
* This function returns the supported byte capacities for the device.
* @param capacities
* Pointer for returning the list of capacities.
* @param capacitiesMaxCount
* The number of capacity values returned in "capacities."
*/
virtual UInt32 getFormatCapacities(UInt64 * capacities,
UInt32 capacitiesMaxCount) const;
/*!
* @function getMediaBlockSize
* @abstract
* Return the block size for the device, in bytes.
*/
virtual UInt64 getMediaBlockSize(void) const;
/*!
* @function getMediaState
* @abstract
* Return the state of media in the device.
*/
virtual IODrive::IOMediaState getMediaState(void) const;
/*!
* @function handleStart
* @abstract
* Handle startup functionality after superclass is ready.
* @discussion
* This function obtains device description strings (e.g. Vendor name), prints
* a message describing the device, and then obtains all removable-media information
* (if the device is removable.) Finally, a check for media is performed.
* @param provider
* A pointer to our provider.
*/
virtual bool handleStart(IOService * provider);
/*!
* @function handleStop
* @abstract
* Handle clean up functionality before driver is unloaded.
* @discussion
* If the media is writable, this method issues a Synchronize Cache operation.
* Then the media is ejected.
* @param provider
* A pointer to our provider.
*/
virtual void handleStop(IOService * provider);
/*!
* @function isMediaEjectable
* @abstract
* Report whether the media is removable or not.
* @result
* True indicates the media can be ejected by software; False indicates it cannot.
*/
virtual bool isMediaEjectable(void) const;
/*!
* @function isMediaPollExpensive
* @abstract
* Report whether polling for media is expensive.
* @result
* True indicates the media poll is expensive; False indicates polling is cheap.
*/
virtual bool isMediaPollExpensive(void) const;
/*!
* @function isMediaPollRequired
* @abstract
* Report whether device must be polled to determine media state.
* @discussion
* @result
* True indicates that polling is required; False indicates that no polling is needed.
*/
virtual bool isMediaPollRequired(void) const;
/*!
* @function lockMedia
* @abstract
* Lock or unlock the media in the device.
* @discussion
* This method may be used to lock the media in the device, thus preventing the user
* from removing the media manually.
*
* This method only makes sense if it is known that the device supports locking.
* @param lock
* True indicates the media should be locked in the device;
* False indicates the media should be unlocked.
*/
virtual IOReturn lockMedia(bool lock);
/*!
* @function pollMedia
* @abstract
* Poll for media insertion/removal.
* @discussion
* This method is called periodically by the superclass, if isMediaPollRequired has
* previously reported True. We are responsible for reacting to new media insertion,
* or to existing media being removed.
*/
virtual IOReturn pollMedia(void);
protected:
/*!
* @function executeRequest
* @abstract
* Start an asynchronous read or write operation.
* @discussion
* This method is the main entry to start an asynchronous read or
* write operation. All IO operations must be block aligned and a
* multiple of the device block size. After some validations, the
* request is passed to the Transport Driver's doAsyncReadWrite method.
* The completion from the operation is set to call RWCompletion, by
* way of the gc_glue C function.
* @param byteStart
* The starting byte offset of the data transfer.
* @param buffer
* The data buffer for the operation. A pointer to an IOMemoryDescriptor.
* @param completion
* The completion information for an asynchronous read or write operation.
*/
virtual void executeRequest(UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageCompletion completion);
/*!
* @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 decommissionMedia
* @abstract
* Decommission an existing piece of media that has gone away.
* @discussion
* This method wraps a call to tearDown, to tear down the stack and
* the IOMedia object for the media. If "forcible" is true, the media
* object will be forgotten, and initMediaStates will be called. A
* forcible decommission would occur when an unrecoverable error
* happens during teardown (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 tearDown 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 media
* A pointer to the created IOMedia object.
* @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 isWholeMedia
* True indicates the IOMedia object represents the entire media; False indicates
* the IOMedia object represents a portion of the entire media.
* @param mediaName
* Name of the IOMedia object.
*/
virtual IOReturn instantiateMediaObject(IOMedia **media,UInt64 base,UInt64 byteSize,UInt32 blockSize,
bool isWholeMedia,char *mediaName);
/*!
* @function recordAdditionalMediaParameters
* @abstract
* Record any additional media parameters as necessary.
* @discussion
* This method is called by recordMediaParameters() when media is detected.
* The default implementation does nothing and returns kIOReturnSuccess. A
* subclass may override this method to record additional parameters.
*/
virtual IOReturn recordAdditionalMediaParameters(void);
/* --- Internally used methods. --- */
/*
* @group
* Internally Used Methods
* @discussion
* These methods are used internally, and will not generally be modified.
*/
/*!
* @function allocateContext
* @abstract
* Allocate a context structure for use with the current async operation.
* @discussion
* A context structure is only needed for asynchronous read or write operations,
* to contain information used to complete the request with the client.
*/
virtual struct IOHDDrive::context *allocateContext(void);
/*!
* @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 Transport Driver's reportMediaState method. If
* reportMediaState reports no change in the media state, kIOReturnSuccess
* is returned. 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 teardown is needed to enforce
* the disappearance of media, regardless of interested clients.
*/
virtual IOReturn checkForMedia(void);
/*!
* @function constructMediaProperties
* @abstract
* Create properties related to the media.
* @discussion
* This function creates a set of properties to express media properties.
*
* This function is presently called by recordMediaParameters, but it does nothing.
*/
virtual OSDictionary *constructMediaProperties(void);
/*!
* @function deleteContext
* @abstract
* Delete a context structure.
* @discussion
* This method also issues a "release" for the IO buffer, if any.
* @param cx
* A pointer to the context structure to be deleted.
*/
virtual void deleteContext(struct IOHDDrive::context *cx);
/*!
* @function getDeviceTypeName
* @abstract
* Return the desired device name.
* @discussion
* This method returns a string, used to compare the kDeviceTypeProperty of
* our provider. This method is called from probe.
*
* The default implementation of this method returns kDeviceTypeHardDisk.
*/
virtual const char * getDeviceTypeName(void);
/*!
* @function initMediaStates
* @abstract
* Initialize media-related instance variables.
* @discussion
* Called when media is not present, this method marks the drive state
* as not having media present, not spun up, and write-enabled.
*/
virtual void initMediaStates(void);
/*!
* @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 setProvider
* @abstract
* Store the provider pointer.
* @discussion
* This method uses IODynamicCast to verify that the provider is of
* the proper class type. The default implementation checks for a nub
* of type IOHDDriveNub.
*
* This method would be overridden for a new generic driver subclass. For
* example, a generic CD driver would need to accept a different provider
* class (e.g. IOCDDriveNub instead of IOHDDriveNub).
* @param provider
* A pointer to our provider.
*/
virtual bool setProvider(IOService * provider);
/*!
* @function showStats
* @abstract
* Print debugging statistics.
* @discussion
* This method prints debugging statistics maintained by the class.
*
* Present statistics include counts of up and down calls.
* @result
* True indicates statistics should be printed; False indicates no printing desired.
*/
virtual bool showStats(void);
/*!
* @function tearDown
* @abstract
* Tear down the stack above this object when media goes away.
* @discussion
* This method calls media->terminate, and if that succeeds, issues
* a release on the media object, followed by a call to initMediaStates.
* @param media
* A pointer to the IOMedia object from which to initiate teardown.
*/
virtual IOReturn tearDown(IOService *media);
/*
* @endgroup
*/
/*!
* @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 (andcall 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);
/*!
* @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 */
public:
/*!
* @function RWCompletion
* @abstract
* Handle a C callback for an IO completion.
* @discussion
* This method must be public so we can reach it from the C-language callback
* "glue" routine. It should not be called from outside this class.
*/
virtual void RWCompletion(struct IOHDDrive::context *cx);
protected:
/* -------------*/
/*!
* @var _provider
* A pointer to our provider.
*/
IOHDDriveNub * _provider;
/* 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 drive */
/*!
* @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;
/* Async IO statistics, usually only useful for debugging. These counters show
* outstanding IO operations and completions.
*/
/*!
* @struct stats
* A data structure to contain debugging statistics. Each field is a count.
* @field clientReceived
* Requests received from our client.
* @field providerSent
* Requests sent to our provider.
* @field providerReject
* Client requests we rejected without sending to our provider.
* @field providerCompletionsRcvd
* Completion calls that have arrived from our provider.
* @field clientCompletionsSent
* Completion calls that have been made to our client.
* @field clientCompletionsDone
* Completion calls to the client that have come back to us.
* This count MUST match clientCompletionsSent!
*/
/*!
* @var stats
* The stats structure.
*/
struct stats { /* executeRequest & completion counts */
int clientReceived; /* requests received from client */
int providerSent; /* requests sent to provider */
int providerReject; /* provider requests rejected */
int providerCompletionsRcvd; /* completions received from provider */
int clientCompletionsSent; /* completions sent to client */
int clientCompletionsDone; /* client completions made it back to us */
} _stats;
/* Media info and states: */
/*!
* @var _mediaObject
* A pointer to the media object we have instantiated (if any).
*/
IOMedia * _mediaObject;
/*!
* @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;
/*!
* @var _mediaStateLock
* A lock used to protect during media checks.
*/
IOLock * _mediaStateLock;
/*!
* @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;
};
#endif