IOBasicSCSI



Member Functions

RWCompletion

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

NameDescription
cxA pointer to the context structure for the completing command.

allocateContext

Abstract: Allocate a context structure for use with the current IO operation.
protected:

virtual struct context * allocateContext(void);


allocateInquiryBuffer

Abstract: Allocate an inquiry buffer.
protected:

virtual IOReturn allocateInquiryBuffer(UInt8 **buf,UInt32 size);

Parameters

NameDescription
bufA pointer for the returned buffer pointer.
sizeThe requested size of the buffer, in bytes.

allocateReadCapacityBuffer

Abstract: Allocate a buffer for Read-Capacity data.
protected:

virtual IOReturn allocateReadCapacityBuffer(UInt8 **buf,UInt8 size);

Parameters

NameDescription
bufA pointer for the returned buffer pointer.
sizeThe requested size of the buffer, in bytes.

allocateTempBuffer

Abstract: Allocate a buffer for temporary use.
protected:

virtual IOReturn allocateTempBuffer(UInt8 **buf,UInt32 size);

Parameters

NameDescription
bufA pointer for the returned buffer pointer.
sizeThe requested size of the buffer, in bytes.

createReadCdb

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

NameDescription
cdbA pointer to the CDB bytes.
cdbLengthThe length of the CDB in bytes.
blockThe device block to be read.
nblksThe number of blocks to be transferred.
maxAutoSenseLengthThe maximum size of the autosense data, in bytes. A value of zero will disable autosense.
timeoutSecondsThe command timeout in seconds.
Result: The IOSCSICommandOptions returned will be used to issue the command.

createWriteCdb

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

NameDescription
cdbA pointer to the CDB bytes.
cdbLengthThe length of the CDB in bytes.
blockThe device block to be written.
nblksThe number of blocks to be transferred.
maxAutoSenseLengthThe maximum size of the autosense data, in bytes. A value of zero will disable autosense.
timeoutSecondsThe command timeout in seconds.
Result: The IOSCSICommandOptions returned will be used to issue the command.

deleteContext

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

NameDescription
cxA pointer to the context structure to be deleted.

deleteInquiryBuffer

Abstract: Delete an inquiry data buffer.
protected:

virtual void deleteInquiryBuffer(UInt8 *buf,UInt32 size);

Parameters

NameDescription
bufA pointer to the buffer.
sizeThe requested size of the buffer, in bytes.

deleteReadCapacityBuffer

Abstract: Delete a Read-Capacity data buffer.
protected:

virtual void deleteReadCapacityBuffer(UInt8 *buf,UInt32 len);

Parameters

NameDescription
bufA pointer to the buffer.
lenThe requested size of the buffer, in bytes.

deleteTempBuffer

Abstract: Delete a temporary data buffer.
protected:

virtual void deleteTempBuffer(UInt8 *buf,UInt32 len);

Parameters

NameDescription
bufA pointer to the buffer.
lenThe requested size of the buffer, in bytes.

dequeueCommands

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.


deviceTypeMatches

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

NameDescription
inqBufA pointer to the SCSI inquiry data for the device.
inqLenThe size of the data in the inquiry buffer.
Result: True indicates a match; False indicates a failure.

doInquiry

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

NameDescription
inqBufA pointer to the buffer.
maxLenThe maximum number of bytes the buffer can contain.
actualLenA pointer to the returned byte count actually transferred.

doReadCapacity

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

NameDescription
blockSizeA pointer to the returned block size value.
maxBlockA pointer to the returned maximum block number.

executeCdb

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

NameDescription
paramsSee IOHDTypes.h for the layout of this data structure.

genericCompletion

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

NameDescription
cxA pointer to the context structure for the command.

getAdditionalDeviceInfoString

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]" .

getBlockSize

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.


getExecuteCDBPowerState

Abstract: Return the required device power level to execute a client CDB.
protected:

virtual UInt32 getExecuteCDBPowerState(void) = 0;


getInquiryPowerState

Abstract: Return the required device power level to issue an Inquiry command.
protected:

virtual UInt32 getInquiryPowerState(void) = 0;


getProductString

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.

getReadCapacityPowerState

Abstract: Return the required device power level to issue a Read Capacity command.
protected:

virtual UInt32 getReadCapacityPowerState(void) = 0;


getReadWritePowerState

Abstract: Return the required device power level to issue a data read or write.
protected:

virtual UInt32 getReadWritePowerState(void) = 0;


getReportWriteProtectionPowerState

Abstract: Return the required device power level to determine media write protection.
protected:

virtual UInt32 getReportWriteProtectionPowerState(void) = 0;


getRevisionString

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.

getVendorString

Abstract: Return Vendor Name string
public:

virtual char * getVendorString(void);

Result: A pointer to a static character string, copied from the inquiry data.

handleUnitAttention

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

NameDescription
cxPointer to context for the current command.

powerTickle

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

NameDescription
desiredStateThe 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.

probe

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.


queueCommand

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

NameDescription
cxThe context for the command being queued.
isSyncTrue if the command is synchronous; False if the command is asynchronous.
desiredPowerThe device power level needed before the command can execute.

reportBlockSize

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

NameDescription
blockSizePointer to returned block size value.

reportEjectability

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

NameDescription
isEjectablePointer to returned result. True indicates the media is ejectable, False indicates the media cannot be ejected under software control.

reportLockability

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

NameDescription
isLockablePointer to returned result. True indicates the media can be locked in place; False indicates the media cannot be locked by software.

reportMaxReadTransfer

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

NameDescription
blockSizeThe block size desired for the transfer.
maxPointer to returned result.

reportMaxValidBlock

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

NameDescription
maxBlockPointer to returned result

reportMaxWriteTransfer

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

NameDescription
blockSizeThe block size desired for the transfer.
maxPointer to returned result.

reportPollRequirements

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

NameDescription
pollRequiredPointer to returned result. True indicates that polling is required; False indicates that polling is not required to detect media.
pollIsExpensivePointer to returned result. True indicates that the polling operation is expensive; False indicates that the polling operation is cheap.

reportRemovability

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

NameDescription
isRemovablePointer to returned result. True indicates that the media is removable; False indicates the media is not removable.

reportWriteProtection

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

NameDescription
isWriteProtectedPointer 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).

simpleSynchIO

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

NameDescription
cxA pointer to the context structure for the command.

standardAsyncReadWrite

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

NameDescription
bufferAn IOMemoryDescriptor describing the data-transfer buffer. The data direction is contained in the IOMemoryDescriptor. Responsiblity for releasing the descriptor rests with the caller.
blockThe starting block number of the data transfer.
nblksThe integral number of blocks to be transferred.
actionThe C function called upon completion of the data transfer.
targetThe C++ class "this" pointer, passed as an argument to "action."
paramThis 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.

standardAsyncReadWriteExecute

Abstract: Issue an asynchronous read/write operation after dequeuing.
protected:

virtual IOReturn standardAsyncReadWriteExecute(struct context *cx);

Parameters

NameDescription
cxA pointer to the context structure for the command.

standardSyncReadWrite

protected:

virtual IOReturn standardSyncReadWrite(IOMemoryDescriptor *buffer,UInt32 block,UInt32 nblks);

Perform a synchronous read or write operation.

Parameters

NameDescription
bufferAn IOMemoryDescriptor describing the data-transfer buffer. The data direction is contained in the IOMemoryDescriptor. Responsiblity for releasing the descriptor rests with the caller.
blockThe starting block number of the data transfer.
nblksThe integral number of blocks to be transferred.

stringFromState

Abstract: Return a string description of a state value.
protected:

virtual char * stringFromState(stateValue state);

Used for debugging.

Parameters

NameDescription
stateThe state to be converted to a string description.

Member Data

_inqBuf

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.


_provider

protected:
 IOSCSIDevice * _provider;

A pointer to our provider.


completion

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

NameDescription
actionThe C function called upon completion of the operation.
targetThe C++ class pointer, passed to tha action function.
paramA value passed to the action function. This value is not touched.

© 2000 Apple Computer, Inc. — (Last Updated 2/23/2000)