The IOBlockStorageDevice Interface

The upper layers of the storage driver stack communicate with the transport driver through a class that is derived from the IOBlockStorageDevice interface. The IOBlockStorageDevice presents a view of the storage device as a linear array of logical blocks that can be either read from or written to by the caller. A logical block is the minimum number of bytes that the disk is capable of reading or writing, and a disk operation must operate on a multiple of blocks. Depending on the disk, the block size will be anywhere from 512 bytes to 4096 bytes. All operations performed by the IOBlockStorageDevice class work on a contiguous range of disk blocks.

The methods that must be implemented by a subclass of the IOBlockStorageDevice interface are described in Listing 14-1. The IOBlockStorageDevice class is not designed to provide a full implementation of the behavior of these methods; instead, it passes them on to its provider class, which is the transport driver within the storage driver stack.

Listing 14-1. The Methods to Be Implemented by a Subclass of the IOBlockStorageDevice Interface

class IOBlockStorageDevice : public IOService
{
        virtual bool            init(OSDictionary * properties);
        virtual IOReturn        doEjectMedia(void) = 0;
        virtual IOReturn        doFormatMedia(UInt64 byteCapacity) = 0;
        virtual UInt32          doGetFormatCapacities(UInt64 * capacities,
                                    UInt32   capacitiesMaxCount) const = 0;
        virtual IOReturn        doLockUnlockMedia(bool doLock) = 0;
        virtual IOReturn        doSynchronizeCache(void) = 0;
        virtual char*           getVendorString(void) = 0;
        virtual char*           getProductString(void) = 0;
        virtual char*           getRevisionString(void) = 0;
        virtual char*           getAdditionalDeviceInfoString(void) = 0;
        virtual IOReturn        reportBlockSize(UInt64 *blockSize) = 0;
        virtual IOReturn        reportEjectability(bool *isEjectable) = 0;
        virtual IOReturn        reportLockability(bool *isLockable) = 0;
        virtual IOReturn        reportMaxValidBlock(UInt64 *maxBlock) = 0;
        virtual IOReturn        reportMediaState(bool *mediaPresent,bool *changedState) = 0;
        virtual IOReturn        reportPollRequirements(bool *pollRequired,
                                    bool *pollIsExpensive) = 0;
        virtual IOReturn        reportRemovability(bool *isRemovable) = 0;
        virtual IOReturn        reportWriteProtection(bool *isWriteProtected) = 0;
        virtual IOReturn        getWriteCacheState(bool *enabled) = 0;
        virtual IOReturn        setWriteCacheState(bool enabled) = 0;
        virtual IOReturn        doAsyncReadWrite(IOMemoryDescriptor *buffer, UInt64 block,
                                    UInt64 nblks, IOStorageAttributes *attributes,
                                    IOStorageCompletion *completion) = 0;
        virtual IOReturn        requestIdle(void);
        virtual IOReturn        doDiscard(UInt64 block, UInt64 nblks);
        virtual IOReturn        doUnmap(IOBlockStorageDeviceExtent* extents,
                                    UInt32 extentsCount, UInt32 options);
};

The following sections describe the methods that a subclass of IOBlockStorageDevice needs to implement, and they are ordered by functionality. The first methods described each return a human readable description of the device to the user. These strings are used to help the user to identify the storage device that corresponds to a mounted volume. If the storage medium has not been formatted, no volume will be associated with the device, and these identification strings will be the only means the user has of ensuring that the device they are about to format is the device they think it is. Therefore, these strings should return a descriptive name that, for example, identifies the manufacturer of a USB flash drive or provides a description of the connection interface (such as “USB to SATA adapter”), allowing the user to easily identify the device. These strings appear in utilities such as “Disk Utility” and the system profiles produced by “System Information.”

  • getVendorString returns the name of the manufacturer of the storage device.
  • getProductString returns a descriptive name of the product model.
  • getRevisionString returns a string whose interpretation can be decided by the driver developer. This could be used to identify the firmware version running on the storage device, or it could provide an identification of the product design. Both values could also be included because the value is a string.
  • getAdditionalDeviceInfoString is currently unused by the I/O Kit implementation, but could be queried from the driver by proprietary disk utility software.

The following methods are called to query the capabilities of the storage device:

  • reportRemovability and reportEjectability both return similar information. A device is considered removable if the media may come and go while the driver is present. This means that the I/O Kit may periodically poll the transport driver to determine whether a disk is currently present. Furthermore, a device that is removable is considered ejectable if it can be removed through software control (such as a CD drive). If a device is not ejectable, the user can still “eject” through the Finder or Disk Utility, although Mac OS X will perform an unmount of the file system, but won't eject the media.
  • reportLockability is called to determine whether the media in a removable drive can be “locked down” and prevented from being removed by the user. An example of locking a device is a CD drive that has an eject button on its front case that can be disabled (locked) when a CD is mounted.
  • reportPollRequirements is called to determine whether the driver needs to be periodically called to check whether media has been inserted or removed, as opposed to the driver itself being able to generate a notification when media has arrived. If the device requires polling, the driver can return an additional flag through the reportPollRequirements method to indicate whether polling is expensive, for example, if media can be detected only by spinning up the device. The I/O Kit will poll a device only if it is not expensive.
  • reportMediaState is called to determine whether there is media present in the device. This method is called once when the storage driver stack is created, to read the initial state of the hardware, and thereafter, only if the driver has indicated that it requires polling to determine the presence of media.

The following methods are called to query the capabilities of the media that is present. These methods are called whenever new media is detected.

  • reportBlockSize should return the size in bytes of a disk sector (or block) for the device. A user space process can access this value through the ioctl DKIOCGETBLOCKSIZE.
  • reportMaxValidBlock returns the capacity of the device, expressed in terms of the address of the final block of the device. Because disk blocks are indexed from 0, the maximum valid block is one less than the total block count of the device.
  • reportWriteProtection is called to determine whether the media can be written to or is write-protected, in which case it will be mounted as a read-only volume. A user space process can access this value through the ioctl DKIOCISWRITABLE.

The following methods perform low-level formatting of the media. Not all devices can support low-level formatting. Even though these methods must be present in the implementation of the IOBlockStorageDevice interface, it is acceptable to return an error if the functionality is not provided.

  • doGetFormatCapacities is called to obtain a list containing each size (in bytes) that the media can be formatted to. The storage to hold the result of this method is provided by the caller, and the method returns the actual number of items that were written to the list. The caller can provide a NULL pointer for the list storage if it wishes to determine the number of formats that the implementation supports, without receiving the actual list. A user space process can request this list through the ioctl DKIOCGETFORMATCAPACITIES.
  • doFormatMedia is called to perform a low-level format of the device. If this functionality is not implemented, the method is free to return an error, such as kIOReturnUnsupported. A user space process can perform this action by sending the ioctl DKIOCFORMAT.
  • The doDiscard method is called not to format the entire disk but rather to wipe blocks that no longer store data that is required by the file system. For a solid state disk, this method provides an opportunity to issue a TRIM command for the discarded blocks. A user space process can perform this action by sending the ioctl DKIOCDISCARD. This method was deprecated in later versions of Mac OS X 10.6 and has been replaced with the doUnmap method.
  • The doUnmap method was introduced as a replacement for the doDiscard method. It performs a similar function, which is to release disk blocks that are not used by the file system. Unlike the doDiscard method, which is capable of releasing only a single physically contiguous run of disk blocks, the doUnmap method is provided with an array containing one or more ranges of disk blocks that are no longer in use. A user space process can perform this action by sending the ioctl DKIOCUNMAP.

The following methods allow software control over ejecting the media:

  • doLockUnlockMedia is called to prevent the user from ejecting the media, such as disabling the eject button on the front of a CD drive. The method is passed a Boolean parameter that determines whether the driver should lock the media in the device (prevent user ejection) or unlock the media (allow user ejection).
  • doEjectMedia is called to eject the media from the device. A user space process can perform this action by sending the ioctl DKIOCEJECT.
  • requestIdle is called to place the disk in an idle state, such as spinning down a CD drive. While there is no corresponding method to take the device out of the idle state, the next read or write operation will implicitly do so. A user space process can perform this action by sending the ioctl DKIOCREQUESTIDLE.

Finally, and perhaps most importantly, are the following methods for reading and writing data to the device:

  • doAsyncReadWrite is the generic data read and write method of the IOBlockStorageDevice interface. It takes as its parameters an IOMemoryDescriptor object that describes the source buffer (for a disk read) or the destination buffer (for a disk write), a contiguous range of disk blocks to read from or write to, and associated attribute flags. The IOMemoryDescriptor also serves to determine whether the requested operation is a read or a write; the driver calls the method getDirection() on the IOMemoryDescriptor object, and if the returned value is kIODirectionIn, a read operation has been requested. If the returned value is kIODirectionOut, a write operation has been requested. The disk operation is performed asynchronously, and when it completes, the caller is notified through a callback function that is provided.
  • setWriteCacheState is called to enable or disable any hardware caching that the device has. The corresponding method getWriteCacheState returns the current state of the device cache.
  • doSynchronizeCache is called to flush the contents of the hardware cache to the media. This is a synchronous method that should not return until the contents of the cache have been written to a disk. This method is also called in response to the ioctl DKIOCSYNCHRONIZECACHE from a user space process.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.2.223