Source to iokit/IOKit/storage/scsi/IOBasicSCSI.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.
*
* IOBasicSCSI.h
*
* This class implements generic SCSI functionality.
*/
#ifndef _IOBASICSCSI_H
#define _IOBASICSCSI_H
#include <IOKit/IOTypes.h>
#include <IOKit/IOService.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/scsi/IOSCSIDeviceInterface.h>
#include <IOKit/storage/IOHDTypes.h>
const int kMinInqSize = 5; /* minimal, supported by all devs */
const int kReadCapSize = 8;
const int kModeSenseSize = 64;
const int kMaxInqSize = 256;
const int kCheckCondition = 0x02;
const int kUnitAttention = 0x06;
/* SCSI operation codes: */
const UInt8 SOP_TUR = 0x00; /* test unit ready */
const UInt8 SOP_INQUIRY = 0x12; /* inquiry */
const UInt8 SOP_MODESELECT = 0x15; /* mode select */
const UInt8 SOP_MODESENSE = 0x1a; /* mode sense */
const UInt8 SOP_READCAP = 0x25; /* read capacity */
const UInt8 SOP_READ10 = 0x28; /* read (10-byte) */
const UInt8 SOP_WRITE10 = 0x2a; /* write (10-byte) */
struct IOTURcdb {
UInt8 opcode;
UInt8 lunbits;
UInt8 reserved1;
UInt8 reserved2;
UInt8 reserved3;
UInt8 ctlbyte;
};
struct IORWcdb { /* CDB for read and write */
UInt8 opcode; /* read=0x28, write=0x2a */
UInt8 lunbits; /* lun and control bits */
UInt8 lba_3; /* logical block address: msb */
UInt8 lba_2;
UInt8 lba_1;
UInt8 lba_0; /* logical block address: lsb */
UInt8 reserved;
UInt8 count_msb; /* block count: msb */
UInt8 count_lsb; /* block count: lsb */
UInt8 ctlbyte;
};
struct IOInquirycdb { /* inquiry */
UInt8 opcode; /* 0x12 */
UInt8 lunbits; /* lun and control bits */
UInt8 pagecode; /* page code/op code */
UInt8 reserved;
UInt8 len; /* allocation length */
UInt8 ctlbyte;
};
struct IOReadCapcdb {
UInt8 opcode;
UInt8 lunbits;
UInt8 lba_3;
UInt8 lba_2;
UInt8 lba_1;
UInt8 lba_0;
UInt8 reserved1;
UInt8 reserved2;
UInt8 reserved3;
UInt8 ctlbyte;
};
struct IOModeSensecdb {
UInt8 opcode;
UInt8 lunbits; /* lun and control bits */
UInt8 pagecode;
UInt8 reserved;
UInt8 len; /* allocation length */
UInt8 ctlbyte;
};
struct IOModeSelectcdb {
UInt8 opcode;
UInt8 lunbits;
UInt8 reserved1;
UInt8 reserved2;
UInt8 paramlen;
UInt8 ctlbyte;
};
/*!
* @enum stateValues
* @discussion
* These state values are used to determin the state of an IO operation.
* Some are simply for debugging use.
* @constant kNone
* Nothing happening.
* @constant kAsyncReadWrite
* Doing an asynchronous IO operation.
* @constant kSimpleSynchIO
* Doing a simple synchronous IO operation.
* @constant kHandlingUnitAttention
* Currently handling a Unit-Attention condition.
* @constant kDoneHandlingUnitAttention
* Done handling Unit Attention; command should be reissued.
* @constant kAwaitingPower
* Awaiting power.
* @constant kMaxValidState
* The maximum valid state value.
* @constant kMaxStateValue
* The maximum state value possible.
*/
enum stateValues {
kNone = 0,
kAsyncReadWrite = 1,
kSimpleSynchIO = 2,
kHandlingUnitAttention = 3,
kDoneHandlingUnitAttention = 4,
kAwaitingPower = 5,
kMaxValidState = kAwaitingPower,
kMaxStateValue = 255
};
/*!
* @typedef statevalue
* @discussion
* Shorthand for enum StateValues.
*/
typedef enum stateValues stateValue;
const bool kSync = true; /* type info for requests awaiting power */
const bool kAsync = false;
/*!
* @class
* IOBasicSCSI : public IOService
* @abstract
* Basic SCSI support functions.
* @discussion
* IOBasicSCSI provides a set of basic SCSI functions and support
* utilities. It is intended to be the base class for a SCSI Transport
* Driver.
*/
class IOBasicSCSI : public IOService {
OSDeclareAbstractStructors(IOBasicSCSI)
public:
/*!
* @struct completion
* @field action
* The C function called upon completion of the operation.
* @field target
* The C++ class pointer, passed to tha action function.
* @field param
* A value passed to the action function. This value is not touched.
*/
/*!
* @struct context
* @discussion
* The context structure contains all persistent information needed for a
* synchronous or asynchronous IO operation.
* @field completion
* The completion information for an asynchronous read or write operation.
* @field state
* The current state of the operation.
* @field step
* The current step value, if we are handling a Unit Attention.
* @field originalContext
* A pointer to the context for the command that caused the Unit Attention
* condition.
* @field scsireq
* A pointer to the IOSCSIRequest object.
* @field memory
* The data buffer for the operation. A pointer to an IOMemoryDescriptor.
* @field scsiresult
* A pointer to the IOSCSIResult object.
* @field desiredPower
* The desired power level for the operation to execute.
* @field isSync
* True if synchronous; False if asynchronous.
* @field next
* A pointer to a context structure, used as a queue forward-link.
* @field sync
* A syncer used to block a thread awaiting a power level, or for completion
* of a synchronous operation.
*/
struct context {
/* Completion information for our client, used only for async operations.
* Typically this information will only be used by subclasses.
*/
struct {
gdCompletionFunction action; /* function to call */
IOService *target; /* client object ("this") */
void *param; /* client's parameter */
} completion;
/* Parameters used during an IO retry: */
stateValue state; /* what state we're in */
UInt32 step;
struct context *originalIOContext; /* original SCSI IO if doing a retry */
IOMemoryDescriptor *memory;
UInt32 desiredPower; /* desired power level state */
bool isSync; /* true if sync, false if async */
struct context *next; /* for queue of requests pending power */
/* Parameters to hand off to the SCSI provider: */
IOSCSICommand *scsireq;
SCSISenseData *senseData;
IOMemoryDescriptor *senseDataDesc;
IOSyncer *sync; /* to wait for completion */
};
/* Overrides from IOService: */
virtual void free(void);
virtual bool init(OSDictionary * properties);
/*!
* @function probe
* @abstract
* Determine if device matches expected type.
* @discussion
* This method is responsible for matching the device type. It calls
* doInquiry to issue a SCSI Inquiry command to the device, then calls
* deviceTypeMatches to ensure that the device type matches the expected
* type. If the device type matches, then the Vendor, Product, and
* Revision strings are copied from the inquiry data, and "this" is
* returned. If the device type does not match, NULL is returned.
*
* The default implementation ignores the score parameter, though that
* parameter is passed to the superclass probe method.
*/
virtual IOService * probe(IOService * provider,SInt32 * score);
/* --- end of IOService overrides --- */
/*!
* @function deviceTypeMatches
* @abstract
* Determine if device type matches expected type.
* @discussion
* This method must be implemented by a device-specific subclass.
* @param inqBuf
* A pointer to the SCSI inquiry data for the device.
* @param inqLen
* The size of the data in the inquiry buffer.
* @result
* True indicates a match; False indicates a failure.
*/
virtual bool deviceTypeMatches(UInt8 inqBuf[],UInt32 inqLen) = 0;
/*!
* @function executeCdb
* Issue the client's cdb as a pass-through.
* @discussion This method is provided to allow developers to issue arbitrary commands
* to the device (via the Transport Driver). Expected uses might include vendor-specific
* commands to support device-based password-protection, or for other vendor features.
*
* This method may not be supported by all Transport Drivers. For example, ATA devices
* do not have a CDB concept; those Transport Drivers will return kIOReturnUnsupported.
* @param params
* See IOHDTypes.h for the layout of this data structure.
*/
virtual IOReturn executeCdb(struct cdbParams *params);
/*!
* @function getAdditionalDeviceInfoString
* @abstract
* Return additional informational string for the device.
* @result
* A pointer to a static character string. The default implementation
* returns "[SCSI]" .
*/
virtual char * getAdditionalDeviceInfoString(void);
/*!
* @function getVendorString
* @abstract
* Return Vendor Name string
* @result
* A pointer to a static character string, copied from the inquiry data.
*/
virtual char * getVendorString(void);
/*!
* @function getProductString
* @abstract
* Return Product Name string for the device.
* @result
A pointer to a static character string, copied from the inquiry data.
*/
virtual char * getProductString(void);
/*!
* @function getRevisionString
* @abstract
* Return Product Revision string for the device.
* @result
* A pointer to a static character string, copied from the inquiry data.
*/
virtual char * getRevisionString(void);
/*!
* @function reportBlockSize
* @abstract
* Report the block size for the device, in bytes.
* @discussion
* This method returns the block size for the media. The default
* implementation obtains the block size from the SCSI Read Capacity
* command. Since the result of the Read Capacity is used by this
* method and reportMaxValidBlock, this method either returns a cached
* value or calls doReadCapacity to issue the command and cache both
* values.
* @param blockSize
* Pointer to returned block size value.
*/
virtual IOReturn reportBlockSize(UInt64 *blockSize);
/*!
* @function reportEjectability
* @abstract
* Report if the media is ejectable under software control.
* @discussion
* This method reports whether the media is ejectable under software
* control. The default implementation always reports that removable
* media is ejectable.
*
* This method should only be called if the media is known to be removable.
* @param isEjectable
* Pointer to returned result. True indicates the media is ejectable, False indicates
* the media cannot be ejected under software control.
*/
virtual IOReturn reportEjectability(bool *isEjectable);
/*!
* @function reportLockability
* @abstract
* Report if the media is lockable under software control.
* @discussion
* This method reports whether the media can be locked under software
* control, to prevent the user from removing the media manually, e.g.
* by pressing a button on the drive. This method is only called by
* the generic driver when the media is known to be removable. The
* default implementation always returns true.
*
* This method should only be called if the media is known to be removable.
* @param isLockable
* Pointer to returned result. True indicates the media can be locked in place; False
* indicates the media cannot be locked by software.
*/
virtual IOReturn reportLockability(bool *isLockable);
/*!
* @function reportMaxReadTransfer
* @abstract
* Report the maximum allowed byte transfer for read operations.
* @discussion
* Some devices impose a maximum data transfer size. Because this limit
* may be determined by the size of a block-count field in a command, the limit may
* depend on the block size of the transfer.
* The default implementation reports blocksize * 65536, which is the maximum
* number of bytes that can be transferred
* in a SCSI command with a standard 16-bit block count field.
* @param blockSize
* The block size desired for the transfer.
* @param max
* Pointer to returned result.
*/
virtual IOReturn reportMaxReadTransfer (UInt64 blocksize,UInt64 *max);
/*!
* @function reportMaxValidBlock
* @abstract
* Report the highest valid block for the device.
* @discussion
* This method reports the maximum allowable block number. The default
* implementation obtains the block number from the SCSI Read Capacity
* command. Since the result of the Read Capacity is used by this
* method and reportBlockSize, this method either returns a cached
* value or calls doReadCapacity to issue the command and cache both
* values.
* @param maxBlock
* Pointer to returned result
*/
virtual IOReturn reportMaxValidBlock(UInt64 *maxBlock);
/*!
* @function reportMaxWriteTransfer
* @abstract
* Report the maximum allowed byte transfer for write operations.
* @discussion
* Some devices impose a maximum data transfer size. Because this limit
* may be determined by the size of a block-count field in a command, the limit may
* depend on the block size of the transfer.
* The default implementation reports blocksize * 65536, which is the maximum
* number of bytes that can be transferred
* in a SCSI command with a standard 16-bit block count field.
* @param blockSize
* The block size desired for the transfer.
* @param max
* Pointer to returned result.
*/
virtual IOReturn reportMaxWriteTransfer(UInt64 blocksize,UInt64 *max);
/*!
* @function reportPollRequirements
* @abstract
* Report if it's necessary to poll for media insertion, and if polling is expensive.
* @discussion
* This method reports whether the device must be polled to detect media
* insertion, and whether a poll is expensive to perform.
*
* The term "expensive" typically implies a device that must be spun-up to detect media,
* as on a PC floppy. Most devices can detect media inexpensively.
*
* The default implementation of this method always reports an
* inexpensive poll (pollIsExpensive = false), and that all removable
* media must be polled.
* @param pollRequired
* Pointer to returned result. True indicates that polling is required; False indicates
* that polling is not required to detect media.
* @param pollIsExpensive
* Pointer to returned result. True indicates that the polling operation is expensive;
* False indicates that the polling operation is cheap.
*/
virtual IOReturn reportPollRequirements(bool *pollRequired,bool *pollIsExpensive);
/*!
* @function reportRemovability
* @abstract
* Report whether the media is removable or not.
* @discussion
* This method reports whether the media is removable, but it does not
* provide detailed information regarding software eject or lock/unlock capability.
*
* The default implementation of this method examines the cached
* Inquiry data to determine if media is removable. If the RMB bit
* (0x80 of Inquiry data byte 1) is set, the media is removable. If
* there is no Inquiry data, the media is reported to be nonremovable.
*
* This method also sets the instance variable _removable.
* @param isRemovable
* Pointer to returned result. True indicates that the media is removable; False
* indicates the media is not removable.
*/
virtual IOReturn reportRemovability(bool *isRemovable);
/*!
* @function reportWriteProtection
* @abstract
* Report whether the media is write-protected or not.
* @discussion
* The default implementation of this method issues a SCSI Mode Sense
* command to test the WP bit( 0x80 of byte 2 of the Mode Sense Header
* data). A request is made for Mode Sense Page 1, though any valid
* page will return a header. If the bit is set, the media is considered
* write-protected.
* @param isWriteProtected
* Pointer to returned result. True indicates that the media is write-protected (it
* cannot be written); False indicates that the media is not write-protected (it
* is permissible to write).
*/
virtual IOReturn reportWriteProtection(bool *isWriteProtected);
protected:
/*!
* @function createReadCdb
* @abstract
* Create a SCSI CDB for a read operation.
* @discussion
* Override this to control the cdb created for a read operation.
* The default implementation creates a 10-byte read command with
* disconnect allowed, 8-byte autosense, and a 2-second timeout.
* @param cdb
* A pointer to the CDB bytes.
* @param cdbLength
* The length of the CDB in bytes.
* @param block
* The device block to be read.
* @param nblks
* The number of blocks to be transferred.
* @param maxAutoSenseLength
* The maximum size of the autosense data, in bytes. A value of zero
* will disable autosense.
* @param timeoutSeconds
* The command timeout in seconds.
* @result
* The IOSCSICommandOptions returned will be used to issue the command.
*/
virtual UInt32 createReadCdb(
UInt8 *cdb, /* in */
UInt32 *cdbLength, /* out */
UInt32 block, /* in */
UInt32 nblks, /* in */
UInt32 *maxAutoSenseLength, /* out */
UInt32 *timeoutSeconds); /* out */
/*!
* @function createWriteCdb
* @abstract
* Create a SCSI CDB for a write operation.
* @discussion
* Override this to control the cdb created for a write operation.
* The default implementation creates a 10-byte write command with
* disconnect allowed, 8-byte autosense, and a 2-second timeout.
* @param cdb
* A pointer to the CDB bytes.
* @param cdbLength
* The length of the CDB in bytes.
* @param block
* The device block to be written.
* @param nblks
* The number of blocks to be transferred.
* @param maxAutoSenseLength
* The maximum size of the autosense data, in bytes. A value of zero
* will disable autosense.
* @param timeoutSeconds
* The command timeout in seconds.
* @result
* The IOSCSICommandOptions returned will be used to issue the command.
*/
virtual UInt32 createWriteCdb(
UInt8 *cdb, /* in */
UInt32 *cdbLength, /* out */
UInt32 block, /* in */
UInt32 nblks, /* in */
UInt32 *maxAutoSenseLength, /* out */
UInt32 *timeoutSeconds); /* out */
/*!
* @function doInquiry
* @abstract
* Obtain SCSI Inquiry data from the device.
* @discussion
* This method issues a SCSI Inquiry command to the device, to obtain
* the result in the supplied buffer. The method first issues an
* inquiry with a 5-byte length, to obtain the full length of the
* devices inquiry data. The second Inquiry command is issued to get
* the full inquiry data (limited to maxLen, of course).
* @param inqBuf
* A pointer to the buffer.
* @param maxLen
* The maximum number of bytes the buffer can contain.
* @param actualLen
* A pointer to the returned byte count actually transferred.
*/
virtual IOReturn doInquiry(UInt8 *inqBuf,UInt32 maxLen,UInt32 *actualLen);
/*!
* @function handleUnitAttention
* @abstract
* @discussion
* Override this to perform any special processing required when
* a Unit-Attention condition is detected. The cx->step value starts at 1 and
* is incremented as each subsequent command is executed. HandleUnitAttention
* is then called again duirng the command completion, until cx->state is
* changed to kDoneHandlingUnitAttention. This repeated calling behavior allows
* handleUnitAttention to issue several commands to the device to recover from
* the Unit-Attention condition. Note that since handleUnitAttention is called
* on the SCSI completion thread, it must not issue blocking operations, but
* should instead call simpleAsyncIO.
*
* The default implementation merely sets the state to
* kDoneHandlingUnitAttention, to allow the original command to be
* reissued.
* @param cx
* Pointer to context for the current command.
*/
virtual void handleUnitAttention(struct context *cx);
/* 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 IO operation.
*/
virtual struct context * allocateContext(void);
/*!
* @function allocateInquiryBuffer
* @abstract
* Allocate an inquiry buffer.
* @param buf
* A pointer for the returned buffer pointer.
* @param size
* The requested size of the buffer, in bytes.
*/
virtual IOReturn allocateInquiryBuffer(UInt8 **buf,UInt32 size);
/*!
* @function allocateTempBuffer
* @abstract
* Allocate a buffer for temporary use.
* @param buf
* A pointer for the returned buffer pointer.
* @param size
* The requested size of the buffer, in bytes.
*/
virtual IOReturn allocateTempBuffer(UInt8 **buf,UInt32 size);
/*!
* @function allocateReadCapacityBuffer
* @abstract
* Allocate a buffer for Read-Capacity data.
* @param buf
* A pointer for the returned buffer pointer.
* @param size
* The requested size of the buffer, in bytes.
*/
virtual IOReturn allocateReadCapacityBuffer(UInt8 **buf,UInt8 size);
/*!
* @function deleteContext
* @abstract
* Delete a context structure.
* @discussion
* This method also issues a "release" for the IO buffer and/or lock, if any.
* @param cx
* A pointer to the context structure to be deleted.
*/
virtual void deleteContext(struct context *cx);
/*!
* @function deleteInquiryBuffer
* @abstract
* Delete an inquiry data buffer.
* @param buf
* A pointer to the buffer.
* @param size
* The requested size of the buffer, in bytes.
*/
virtual void deleteInquiryBuffer(UInt8 *buf,UInt32 size);
/*!
* @function deleteTempBuffer
* @abstract
* Delete a temporary data buffer.
* @param buf
* A pointer to the buffer.
* @param len
* The requested size of the buffer, in bytes.
*/
virtual void deleteTempBuffer(UInt8 *buf,UInt32 len);
/*!
* @function deleteReadCapacityBuffer
* @abstract
* Delete a Read-Capacity data buffer.
* @param buf
* A pointer to the buffer.
* @param len
* The requested size of the buffer, in bytes.
*/
virtual void deleteReadCapacityBuffer(UInt8 *buf,UInt32 len);
/*!
* @function doReadCapacity
* @abstract
* @discussion
* The default implementation of this method issues a standard SCSI
* Read Capacity command. The block size and maximum valid block are
* extracted from the returned data in an endian-neutral way.
* @param blockSize
* A pointer to the returned block size value.
* @param maxBlock
* A pointer to the returned maximum block number.
*/
virtual IOReturn doReadCapacity(UInt64 *blockSize,UInt64 *maxBlock);
/*!
* @function getBlockSize
* @abstract
* Return the device block size.
* @discussion
* This method obtains the block size from the Read-Capacity data. If RC data is
* not yet cached, a call is made to doReadCapacity to obtain the data.
*/
virtual UInt64 getBlockSize(void);
/*!
* @function dequeueCommands
* @abstract
* Dequeue commands previously enqueued awaiting the proper device power level.
* @discussion
* This method is called when a command is queued (from queueCommand), when a call
* completes (from RWCompletion), and when the device power level changes. All commands
* for which the device power level is proper are immediately dequeued.
*
* Queued synchronous commands are simply "awakened" by unlocking a lock. The originating
* thread then continues and issues the command. Asynchronous commands are immediately
* dispatched via a call to standardAsyncReadWriteExecute.
*/
virtual void dequeueCommands(void);
/*!
* @function queueCommand
* @abstract
* Queue commands awaiting the proper device power level.
* @discussion
* This method is called prior to issuing any IO command, so that each command can
* be enqueued awaiting its desired device power level. After queuing the command, a
* call is made to dequeueCommands to attempt to dequeue any available command that can
* be executed (including the one just queued). Putting commands into the queue ensures
* that the proper sequence is maintained.
* @param cx
* The context for the command being queued.
* @param isSync
* True if the command is synchronous; False if the command is asynchronous.
* @param desiredPower
* The device power level needed before the command can execute.
*/
virtual void queueCommand(struct context *cx,bool isSync,UInt32 desiredPower);
/*!
* @function RWCompletion
* @abstract
* Asynchronous read/write completion routine.
* @discussion
* A subclass must implement the read-write completion, called upon completion
* of an IO started by doAsyncReadWrite.
* @param cx
* A pointer to the context structure for the completing command.
*/
virtual void RWCompletion(struct context *cx) = 0;
/*!
* @function simpleSynchIO
* @abstract
* Issue a simple synchronous SCSI command.
* @discussion
* This method issues a single SCSI command and waits for the command
* to complete. The SCSI command must already be set up in the context
* structure.
* @param cx
* A pointer to the context structure for the command.
*/
virtual IOReturn simpleSynchIO(struct context *cx);
/*!
* @function standardAsyncReadWrite
* @abstract
* Start an asynchronous read or write operation.
* @discussion
* This method starts an asynchronous read or write operation. No
* incoming parameters are validated. The default implementation
* calls createReadCdb or createWriteCdb,
* then issues a SCSI command to IOSCSIDevice. If the command is
* accepted, then the completion will be called at some future time.
* @result
* The only possible returns from this method are:
*
* kIOReturnSuccess, meaning that the IO was accepted by the transport
* drivers provider (e.g. IOSCSIDevice), and that the completion
* function will be called when the IO completes, i.e. target->action(param).
*
* kIOReturnNoMemory, meaning that memory allocation failed.
*
* Other kIOReturn codes from the provider which occurred
* because the IO was not accepted in that provider's queue. This
* might indicate a full queue or bad parameter.
* @param buffer
* An IOMemoryDescriptor describing the data-transfer buffer. The data direction
* is contained in the IOMemoryDescriptor. Responsiblity for releasing the descriptor
* rests with the caller.
* @param block
* The starting block number of the data transfer.
* @param nblks
* The integral number of blocks to be transferred.
* @param action
* The C function called upon completion of the data transfer.
* @param target
* The C++ class "this" pointer, passed as an argument to "action."
* @param param
* This value is passed as an argument to "action." It is not validated or modified.
*/
virtual IOReturn standardAsyncReadWrite(IOMemoryDescriptor *buffer,
UInt32 block,UInt32 nblks,
gdCompletionFunction action,
IOService *target,void *param);
/*!
* @function standardAsyncReadWriteExecute
* @abstract
* Issue an asynchronous read/write operation after dequeuing.
* @param cx
* A pointer to the context structure for the command.
*/
virtual IOReturn standardAsyncReadWriteExecute(struct context *cx);
/*!
* @function standardSyncReadWrite
* Perform a synchronous read or write operation.
* @param buffer
* An IOMemoryDescriptor describing the data-transfer buffer. The data direction
* is contained in the IOMemoryDescriptor. Responsiblity for releasing the descriptor
* rests with the caller.
* @param block
* The starting block number of the data transfer.
* @param nblks
* The integral number of blocks to be transferred.
*/
virtual IOReturn standardSyncReadWrite(IOMemoryDescriptor *buffer,UInt32 block,UInt32 nblks);
/*!
* @function stringFromState
* @abstract
* Return a string description of a state value.
* @discussion
* Used for debugging.
* @param state
* The state to be converted to a string description.
*/
virtual char * stringFromState(stateValue state);
public:
/*!
* @function genericCompletion
* @abstract
* Generic IO completion function.
* @discussion
* This method handles completion of a SCSI command. It implements a
* simple state machine to handle a Unit Attention condition on a
* command.
*
* 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.
*
*
*
* If a Unit Attention condition occurs, we set the state to
* kHandlingUnitAttention and call handleUnitAttention to do whatever
* is necessary to clear the condition. Eventually, handleUnitAttention
* resets the state to kDoneHandlingUnitAttention, which will allow
* the state machine to reissue the original command.
*
* If we are already processing a Unit Attention, then genericCompletion
* increments a step counter and calls handleUnitAttention. The step
* counter allows handleUnitAttention to issue multiple SCSI commands
* to clear the condition. The handleUnitAttention method is called
* repeatedly, until the state is set to kDoneHandlingUnitAttention.
*
* If this operation is a normal asynchronous read or write (usually
* started by standardAsyncReadWrite, though this is not required),
* then a call is made to RWCompletion, followed by deletion of the
* context structure for the command. RWCompletion is implemented by
* the subclass of IOBasicSCSI, for example in IOSCSIHDDrive.
* @param cx
* A pointer to the context structure for the command.
*/
virtual void genericCompletion(struct context *cx);
/*
* @endgroup
*/
protected:
/*
* @group
* Power Management Methods
* @discussion
* A subclass must implement these to report the power level required to do various commands.
*/
/*!
* @function getExecuteCDBPowerState
* @abstract
* Return the required device power level to execute a client CDB.
*/
virtual UInt32 getExecuteCDBPowerState(void) = 0;
/*!
* @function getInquiryPowerState
* @abstract
* Return the required device power level to issue an Inquiry command.
*/
virtual UInt32 getInquiryPowerState(void) = 0;
/*!
* @function getReadCapacityPowerState
* @abstract
* Return the required device power level to issue a Read Capacity command.
*/
virtual UInt32 getReadCapacityPowerState(void) = 0;
/*!
* @function getReadWritePowerState
* @abstract
* Return the required device power level to issue a data read or write.
*/
virtual UInt32 getReadWritePowerState(void) = 0;
/*!
* @function getReportWriteProtectionPowerState
* @abstract
* Return the required device power level to determine media write protection.
*/
virtual UInt32 getReportWriteProtectionPowerState(void) = 0;
/*!
* @function powerTickle
* @abstract
* Check for the device power state currently being in the desired state.
* @discussion
* A subclass must implement powerTickle, which is called when we desire power to
* execute a command. PowerTickle may handle generic or a subclass-expanded set of
* power states. The implementation will usually relay the call to the Power Management
* subsystem function activityTickle. For a device without power management capability,
* the implementation should always return True.
* @param desiredState
* The desired device power level.
* @result
* True if power is in the desired state (or better); False if the caller must wait
* until power is available.
*/
virtual bool powerTickle(UInt32 desiredState) = 0;
/*
* @endgroup
*/
/*!
* @var _provider
* A pointer to our provider.
*/
IOSCSIDevice * _provider;
/* Device information : */
/*!
* @var _inqBuf
* A pointer to the allocate Inquiry Data buffer.
*/
UInt8 * _inqBuf; /* the Inquiry data buffer */
/*!
* @var _inqBufSize
* The size of the inquiry data buffer, in bytes.
*/
UInt32 _inqBufSize; /* size of the buffer */
/*!
* @var _inqLen
* The number of valid bytes of inquiry data.
*/
UInt32 _inqLen; /* valid bytes in buffer */
/*!
* @var _vendor
* The Vendor Name string from the inquiry data, null-terminated.
*/
char _vendor[9]; /* info from Inquiry data */
/*!
* @var _product
* The Product Name string from the inquiry data, null-terminated.
*/
char _product[17];
/*!
* @var _rev
* The Product Revision string from the inquiry data, null-terminated.
*/
char _rev[5];
/* Since we get both of these items from the same command, we
* just cache both values if we get either call, so we only
* have to issue the command once.
*/
/*!
* @var _readCapDone
* True if we have issued a Read-Capacity command to obtain the
* values for _maxBlock and _blockSize.
*/
bool _readCapDone;
/*!
* @var _removable
* True if the media is removable; False if the media is fixed.
*/
bool _removable;
/*!
* @var _maxBlock
* The highest valid block on the media, relative to zero.
*/
UInt64 _maxBlock;
/*!
* @var _blockSize
* The block size of the media in bytes.
*/
UInt64 _blockSize;
/* The queue of pending requests awaiting power: */
/*!
* @struct queue
* @discussion
* A data structure for a queue.
* @field head
* A pointer to the head item.
* @field tail
* A pointer to the tail item.
* @field lock
* A lock used to protect the queue during changes.
*/
/*!
* @var _powerQueue
* A queue structure containing operations queued awaiting power level.
*/
struct queue {
struct context * head;
struct context * tail;
IOLock * lock;
} _powerQueue;
};
#endif