IOBasicSCSI
Member Functions
Abstract: Asynchronous read/write completion routine.
protected:
virtual void RWCompletion(struct context *cx) = 0;
A subclass must implement the read-write completion, called upon completion
of an IO started by doAsyncReadWrite.
Parameters
Name | Description |
cx | A pointer to the context structure for the completing command. |
Abstract: Allocate a context structure for use with the current IO operation.
protected:
virtual struct context * allocateContext(void);
Abstract: Allocate an inquiry buffer.
protected:
virtual IOReturn allocateInquiryBuffer(UInt8 **buf,UInt32 size);
Parameters
Name | Description |
buf | A pointer for the returned buffer pointer. |
size | The requested size of the buffer, in bytes. |
Abstract: Allocate a buffer for Read-Capacity data.
protected:
virtual IOReturn allocateReadCapacityBuffer(UInt8 **buf,UInt8 size);
Parameters
Name | Description |
buf | A pointer for the returned buffer pointer. |
size | The requested size of the buffer, in bytes. |
Abstract: Allocate a buffer for temporary use.
protected:
virtual IOReturn allocateTempBuffer(UInt8 **buf,UInt32 size);
Parameters
Name | Description |
buf | A pointer for the returned buffer pointer. |
size | The requested size of the buffer, in bytes. |
Abstract: Create a SCSI CDB for a read operation.
protected:
virtual UInt32 createReadCdb(
UInt8 *cdb, /* in */
UInt32 *cdbLength, /* out */
UInt32 block, /* in */
UInt32 nblks, /* in */
UInt32 *maxAutoSenseLength, /* out */
UInt32 *timeoutSeconds); /* out */
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.
Parameters
Name | Description |
cdb | A pointer to the CDB bytes. |
cdbLength | The length of the CDB in bytes. |
block | The device block to be read. |
nblks | The number of blocks to be transferred. |
maxAutoSenseLength | The maximum size of the autosense data, in bytes. A value of zero
will disable autosense. |
timeoutSeconds | The command timeout in seconds. |
Result: The IOSCSICommandOptions returned will be used to issue the command.
Abstract: Create a SCSI CDB for a write operation.
protected:
virtual UInt32 createWriteCdb(
UInt8 *cdb, /* in */
UInt32 *cdbLength, /* out */
UInt32 block, /* in */
UInt32 nblks, /* in */
UInt32 *maxAutoSenseLength, /* out */
UInt32 *timeoutSeconds); /* out */
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.
Parameters
Name | Description |
cdb | A pointer to the CDB bytes. |
cdbLength | The length of the CDB in bytes. |
block | The device block to be written. |
nblks | The number of blocks to be transferred. |
maxAutoSenseLength | The maximum size of the autosense data, in bytes. A value of zero
will disable autosense. |
timeoutSeconds | The command timeout in seconds. |
Result: The IOSCSICommandOptions returned will be used to issue the command.
Abstract: Delete a context structure.
protected:
virtual void deleteContext(struct context *cx);
This method also issues a "release" for the IO buffer and/or lock, if any.
Parameters
Name | Description |
cx | A pointer to the context structure to be deleted. |
Abstract: Delete an inquiry data buffer.
protected:
virtual void deleteInquiryBuffer(UInt8 *buf,UInt32 size);
Parameters
Name | Description |
buf | A pointer to the buffer. |
size | The requested size of the buffer, in bytes. |
Abstract: Delete a Read-Capacity data buffer.
protected:
virtual void deleteReadCapacityBuffer(UInt8 *buf,UInt32 len);
Parameters
Name | Description |
buf | A pointer to the buffer. |
len | The requested size of the buffer, in bytes. |
Abstract: Delete a temporary data buffer.
protected:
virtual void deleteTempBuffer(UInt8 *buf,UInt32 len);
Parameters
Name | Description |
buf | A pointer to the buffer. |
len | The requested size of the buffer, in bytes. |
Abstract: Dequeue commands previously enqueued awaiting the proper device power level.
protected:
virtual void dequeueCommands(void);
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.
Abstract: Determine if device type matches expected type.
public:
virtual bool deviceTypeMatches(UInt8 inqBuf[],UInt32 inqLen) = 0;
This method must be implemented by a device-specific subclass.
Parameters
Name | Description |
inqBuf | A pointer to the SCSI inquiry data for the device. |
inqLen | The size of the data in the inquiry buffer. |
Result: True indicates a match; False indicates a failure.
Abstract: Obtain SCSI Inquiry data from the device.
protected:
virtual IOReturn doInquiry(UInt8 *inqBuf,UInt32 maxLen,UInt32 *actualLen);
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).
Parameters
Name | Description |
inqBuf | A pointer to the buffer. |
maxLen | The maximum number of bytes the buffer can contain. |
actualLen | A pointer to the returned byte count actually transferred. |
protected:
virtual IOReturn doReadCapacity(UInt64 *blockSize,UInt64 *maxBlock);
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.
Parameters
Name | Description |
blockSize | A pointer to the returned block size value. |
maxBlock | A pointer to the returned maximum block number. |
public:
virtual IOReturn executeCdb(struct cdbParams *params);
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.
Parameters
Name | Description |
params | See IOHDTypes.h for the layout of this data structure. |
Abstract: Generic IO completion function.
public:
virtual void genericCompletion(struct context *cx);
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.
Parameters
Name | Description |
cx | A pointer to the context structure for the command. |
Abstract: Return additional informational string for the device.
public:
virtual char * getAdditionalDeviceInfoString(void);
Result: A pointer to a static character string. The default implementation
returns "[SCSI]" .
Abstract: Return the device block size.
protected:
virtual UInt64 getBlockSize(void);
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.
Abstract: Return the required device power level to execute a client CDB.
protected:
virtual UInt32 getExecuteCDBPowerState(void) = 0;
Abstract: Return the required device power level to issue an Inquiry command.
protected:
virtual UInt32 getInquiryPowerState(void) = 0;
Abstract: Return Product Name string for the device.
public:
virtual char * getProductString(void);
Result: A pointer to a static character string, copied from the inquiry data.
Abstract: Return the required device power level to issue a Read Capacity command.
protected:
virtual UInt32 getReadCapacityPowerState(void) = 0;
Abstract: Return the required device power level to issue a data read or write.
protected:
virtual UInt32 getReadWritePowerState(void) = 0;
Abstract: Return the required device power level to determine media write protection.
protected:
virtual UInt32 getReportWriteProtectionPowerState(void) = 0;
Abstract: Return Product Revision string for the device.
public:
virtual char * getRevisionString(void);
Result: A pointer to a static character string, copied from the inquiry data.
Abstract: Return Vendor Name string
public:
virtual char * getVendorString(void);
Result: A pointer to a static character string, copied from the inquiry data.
protected:
virtual void handleUnitAttention(struct context *cx);
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.
Parameters
Name | Description |
cx | Pointer to context for the current command. |
Abstract: Check for the device power state currently being in the desired state.
protected:
virtual bool powerTickle(UInt32 desiredState) = 0;
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.
Parameters
Name | Description |
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.
Abstract: Determine if device matches expected type.
public:
virtual IOService * probe(IOService * provider,SInt32 * score);
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.
Abstract: Queue commands awaiting the proper device power level.
protected:
virtual void queueCommand(struct context *cx,bool isSync,UInt32 desiredPower);
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.
Parameters
Name | Description |
cx | The context for the command being queued. |
isSync | True if the command is synchronous; False if the command is asynchronous. |
desiredPower | The device power level needed before the command can execute. |
Abstract: Report the block size for the device, in bytes.
public:
virtual IOReturn reportBlockSize(UInt64 *blockSize);
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.
Parameters
Name | Description |
blockSize | Pointer to returned block size value. |
Abstract: Report if the media is ejectable under software control.
public:
virtual IOReturn reportEjectability(bool *isEjectable);
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.
Parameters
Name | Description |
isEjectable | Pointer to returned result. True indicates the media is ejectable, False indicates
the media cannot be ejected under software control. |
Abstract: Report if the media is lockable under software control.
public:
virtual IOReturn reportLockability(bool *isLockable);
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.
Parameters
Name | Description |
isLockable | Pointer to returned result. True indicates the media can be locked in place; False
indicates the media cannot be locked by software. |
Abstract: Report the maximum allowed byte transfer for read operations.
public:
virtual IOReturn reportMaxReadTransfer(UInt64 blocksize,UInt64 *max);
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.
Parameters
Name | Description |
blockSize | The block size desired for the transfer. |
max | Pointer to returned result. |
Abstract: Report the highest valid block for the device.
public:
virtual IOReturn reportMaxValidBlock(UInt64 *maxBlock);
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.
Parameters
Name | Description |
maxBlock | Pointer to returned result |
Abstract: Report the maximum allowed byte transfer for write operations.
public:
virtual IOReturn reportMaxWriteTransfer(UInt64 blocksize,UInt64 *max);
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.
Parameters
Name | Description |
blockSize | The block size desired for the transfer. |
max | Pointer to returned result. |
Abstract: Report if it's necessary to poll for media insertion, and if polling is expensive.
public:
virtual IOReturn reportPollRequirements(bool *pollRequired,bool *pollIsExpensive);
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.
Parameters
Name | Description |
pollRequired | Pointer to returned result. True indicates that polling is required; False indicates
that polling is not required to detect media. |
pollIsExpensive | Pointer to returned result. True indicates that the polling operation is expensive;
False indicates that the polling operation is cheap. |
Abstract: Report whether the media is removable or not.
public:
virtual IOReturn reportRemovability(bool *isRemovable);
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.
Parameters
Name | Description |
isRemovable | Pointer to returned result. True indicates that the media is removable; False
indicates the media is not removable. |
Abstract: Report whether the media is write-protected or not.
public:
virtual IOReturn reportWriteProtection(bool *isWriteProtected);
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.
Parameters
Name | Description |
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). |
Abstract: Issue a simple synchronous SCSI command.
protected:
virtual IOReturn simpleSynchIO(struct context *cx);
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.
Parameters
Name | Description |
cx | A pointer to the context structure for the command. |
Abstract: Start an asynchronous read or write operation.
protected:
virtual IOReturn standardAsyncReadWrite(IOMemoryDescriptor *buffer,
UInt32 block,UInt32 nblks,
gdCompletionFunction action,
IOService *target,void *param);
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.
Parameters
Name | Description |
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. |
block | The starting block number of the data transfer. |
nblks | The integral number of blocks to be transferred. |
action | The C function called upon completion of the data transfer. |
target | The C++ class "this" pointer, passed as an argument to "action." |
param | This value is passed as an argument to "action." It is not validated or modified. |
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.
Abstract: Issue an asynchronous read/write operation after dequeuing.
protected:
virtual IOReturn standardAsyncReadWriteExecute(struct context *cx);
Parameters
Name | Description |
cx | A pointer to the context structure for the command. |
protected:
virtual IOReturn standardSyncReadWrite(IOMemoryDescriptor *buffer,UInt32 block,UInt32 nblks);
Perform a synchronous read or write operation.
Parameters
Name | Description |
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. |
block | The starting block number of the data transfer. |
nblks | The integral number of blocks to be transferred. |
Abstract: Return a string description of a state value.
protected:
virtual char * stringFromState(stateValue state);
Used for debugging.
Parameters
Name | Description |
state | The state to be converted to a string description. |
Member Data
protected:
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;
};
A pointer to the allocate Inquiry Data buffer.
protected:
IOSCSIDevice * _provider;
A pointer to our provider.
public:
* @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;
Fields
Name | Description |
action | The C function called upon completion of the operation. |
target | The C++ class pointer, passed to tha action function. |
param | A value passed to the action function. This value is not touched. |
© 2000 Apple Computer, Inc. (Last Updated 2/23/2000)