Home > USB Central > Mass Storage Page > The Mass Storage FAQ
The Mass Storage FAQ
Frequently asked questions relating to designing hardware and writing program code for USB devices in the Mass Storage class
This FAQ contains questions frequently asked on the USB Developer's Forum and other questions I've received by e-mail. The FAQ is a supplement to the information on my Mass Storage Page. Suggestions and contributions welcome via
General
How long can a device return NAK in a mass-storage bulk transfer?
The mass-storage specification doesn't define a timeout value. Hosts typically wait 20-30 seconds.
Can my device's firmware read and store files when the device isn't attached to a host?
Yes, if the firmware supports a file system such as FAT16 or FAT32. Note that the mass-storage device should have only one mass-storage master at a time. When the device is attached to and configured by a USB host, the firmware shouldn't attempt to read or write to files on its own.
SCSI
What is the SCSI transparent command set?
In the Mass Storage Class Specification Overview, Table 2.1 says that devices with subclass code 06h implement the "SCSI transparent command set." The SCSI specifications are available from www.t10.org, but these documents don't mention a transparent command set.
According to its creator, subclass 06h means that the host should determine the device type by issuing a SCSI INQUIRY command. In the returned INQUIRY data, bits 4..0 of byte 0 specify a peripheral device type (PDT). The SCSI Primary Commands (SPC) specification defines various PDTs and the specifications they should comply with.
What value should I use for bInterfaceSubClass in the interface descriptor?
New designs should use bInterfaceSubClass = 06h (SCSI transparent
command set). The device's response to a SCSI INQUIRY command is then
the single source where the device declares its command set (via the PERIPHERAL
DEVICE TYPE (PDT) and VERSION codes). A device should use a different
bInterfaceSubClass only if it must for some reason adhere to a command
set that has no PDT code (such as SFF-8070i). See the SPC document for
a list of PDTs.
What commands should my device support?
In the response to a SCSI INQUIRY command, a device returns a PERIPHERAL DEVICE TYPE code and a VERSION code. For hard drives, flash drives, and similar devices, PERIPHERAL DEVICE TYPE = 00h (direct access block device) and VERSION = 04h (SPC-2) or 05h (SPC-3). The code in the VERSION corresponds to a command set, and the command set's specification lists mandatory commands.
In some cases, additional INQUIRY data can provide more information, including vendor-specific data, but not every host will retrieve more than the first 36 bytes of the response.
The SPC specification documents the INQUIRY command. Also see the specification for your device type for any device-specific information about the INQUIRY response.
In practice, many devices don't implement every mandatory command and just concentrate on the commands used by any hosts the device is likely to connect to.
The Mass Storage Class Compliance Test Specification names required and optional commands for different PDTs that want to pass USB-IF's mass-storage compliance tests (under development).
What is command 0x23 (23h)? I can't find it in the SPC or SBC documents.
Command 23h is READ FORMAT CAPACITIES in the Multimedia Commands (MMC) spec from t10.org.
Windows Specific
Can my device use the Reduced Block Command (RBC) set?
Windows doesn't support RBC (bInterfaceSubClass 01h or 06h and PDT = 0Eh), so if you design an RBC device, you'll need to provide a driver for the host. The USB mass storage overview document from usb.org incorrectly says that flash drives typically use RBC. Flash drives use bInterfaceSubClass 06h (SCSI transparent command set) with PDT = 00h (direct-access block device), the same as hard drives.
How can I determine the drive letter Windows has assigned to a USB drive?
Here are three sources of information:
1. How to get the usbdisk's drive letter properly. Using DeviceIoControl to get a USB drive's letter. From f22_storm.
2. (From Marc Reinig) Look at the code that Devcon.exe (from the DDK) uses in
Devcon.exe find =diskdrive
This will give you the instance ID of the disks present on the system, in order of their disk number. 0, 1, 2, 3, . So now you know what the disk number is for your device.
Then, using the code below, loop through all possible 26 logical drives, using strings that look like C: for szDriveLetter. When you get an sdnDevNumber.DeviceNumber that matches the disk number you are looking for, you have found your drive letter, szDriveLetter:
Code:
char szDriveLetter [ 3 ];
char * pszDrive;
STORAGE_DEVICE_NUMBER sdnDevNumber;
BOOL fResult;
fResult = GetBasicDiskDriveMapping ( szDriveLetter, &sdnDevNumber
);
// sdnDevNumber.DeviceNumber will contain the drive number you want
// sdnDevNumber.PartitionNumber will contain the partition for your reference
BOOL
GetBasicDiskDriveMapping ( LPCSTR pszDrive, STORAGE_DEVICE_NUMBER *psdn
)
{
BOOL fResult;
char szDriveName [ 7 ];
HANDLE hDrive;
DWORD dwBytesReturned;
__try
{
lstrcpy ( szDriveName, "\\\\.\\" );
lstrcat ( szDriveName, pszDrive );
// Open the volume to which the drive letter refers and get
// the physical drive on which the volume resides.
hDrive = CreateFile ( szDriveName, GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
OPEN_EXISTING, 0, 0 );
if ( INVALID_HANDLE_VALUE != hDrive )
fResult = DeviceIoControl ( hDrive,
IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0,
psdn, sizeof (STORAGE_DEVICE_NUMBER),
&dwBytesReturned, 0 );
else
fResult = false;
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{ // if we get here, one of the arguments probably
// points to not enough memory.
SetLastError ( ERROR_INVALID_PARAMETER );
fResult = false;
}
CloseHandle ( hDrive );
return ( fResult );
}
3. Also see the Usenet thread How to match between physical usb device and its drive letter.
