Responding to Commands

22 Mar

Responding to Commands
In mass-storage communications that use SCSI commands, the USB host sends a command block, the host or device may send data, and the device returns status. When reading or writing blocks of data, the host identifies the locations to read or write to by specifying a logical block address. The USB communications don’t have to know or care anything about files, directories, or data clusters in the media.

In the bulk-only transport protocol, a successful communication has two or three phases: command transport, data transport (not used for some commands),
and status transport. (Don’t confuse these phases with the phases of a USB transaction or the stages of a USB control transfer.) In the command- transport phase, the host sends a command block in a structure called a command block wrapper (CBW). In the data-transport phase, the host or device sends data. Some commands don’t have a data-transport phase. In the status-transport phase, the device sends status information in a structure called a command status wrapper (CSW).

The mass-storage and SCSI specifications don’t define how long a host should wait for a device to return requested data or accept received data before giving up. The drivers in Windows and other operating systems typically wait 20–30 seconds.

The Command Block Wrapper
The host sends the CBW to the device’s bulk OUT endpoint. The CBW contains a command block and other information about the command (Table 3-6). The CBW is 31 bytes.

Table 3-6: The CBW contains a command descriptor block and other information about the command.

The _USB_MSD_CBW structure can hold a CBW:
#define MSD_CBW_SIZE 0×1F
typedef struct _USB_MSD_CBW
{
dword dCBWSignature;
dword dCBWTag;
dword dCBWDataTransferLength;
byte bCBWFlags;
byte bCBWLUN;
byte bCBWCBLength;
byte CBWCB[16];
} USB_MSD_CBW;

The CBWCB field of a CBW contains a command descriptor block (CDB), or command block for short. The CDB is a structure that contains a command and supplementary information that varies with the command. The CBWCB field is always 16 bytes, but many CDBs are shorter than 16 bytes. Any remaining bytes in the CDB are pad bytes of zero.

In most cases, the bCBWCBLength field indicates the length of the CDB within the CBWCB field excluding pad bytes. For devices with bInterface- SubClass = 04h (UFI), the host must pad CDBs shorter than 12 bytes with zeroes and set bCBWCBLength to 12. For CBWs carrying the 6-byte SCSI REQUEST SENSE command block, the Windows mass-storage driver incorrectly sets bCBWCBLength = 12 even for non-UFI devices.

The bmCBWFlags field indicates the direction of the data-transport phase. The dCBWDataTransferLength field indicates how many bytes the host will send or how many bytes the host expects to receive.

On receiving a CBW, a device should check that the structure is valid and has meaningful content. A CBW is valid if all of the following are true:

• The CBW is received after a CSW or reset.
• The CBW is 31 bytes.
• The dCBWSignature field has the correct value.

The contents are considered meaningful if all of the following are true:
• All of the reserved bits are zero.
• The bCBWLUN field contains a supported LUN value.

• The bCBWCBLength and CBWCB fields are valid for the interface’s subclass.

The IsValidCBW function checks a CBW’s size and signature. The function uses the MSD_BD_OUT identifier defined in Chapter 2 for the bulk OUT endpoint buffer descriptor.

byte gblCBWLength;
USB_MSD_CBW gblCBW;
gblCBWLength = MSD_BD_OUT.Cnt;
byte IsValidCBW()
{
// A valid CBW is 31 bytes and
// its dCBWSignature field contains 0×43425355.
if ((gblCBWLength != MSD_CBW_SIZE) ||
(gblCBW.dCBWSignature != 0×43425355))
return FALSE;
else
return TRUE;
}

The IsMeaningfulCBW function checks for bCBWLUN less than or equal to 0Fh, bCBWCBLength of 01h to 10h bytes, and bCBWFlags equal to 00h or 80h. Note that a meaningful CBW must have a LUN value that is valid for the specific device. (Few devices have 16 LUNs.)

byte IsMeaningfulCBW()
{
if ((gblCBW.bCBWLUN <= 0×0f) &&
(gblCBW.bCBWCBLength <= 0×10) &&
(gblCBW.bCBWCBLength >= 0×01) &&
(gblCBW.bCBWFlags == 0×00 | gblCBW.bCBWFlags == 0×80))
return TRUE;
else
return FALSE;
}

After receiving a CBW, depending on the command, the device must prepare to receive data from the host on the bulk OUT endpoint or prepare to send data or a CSW to the host on the bulk IN endpoint.

Random Posts

No comments yet

Leave a Reply

You must be logged in to post a comment.