Block Commands

25 Mar

Block Commands
Each of the commands below is documented in the SCSI Block Commands (SBC) specification.
FORMAT UNIT
The FORMAT UNIT command requests a device to divide its storage media into logical blocks that applications can access. If the host previously sent a MODE SELECT command, the device should use the number of blocks and block length specified in that command. Otherwise the device should use its current number of blocks and block length.

A device that uses MultiMediaCards or other formatted, removable media might have no need to format its media, but the SBC specification lists the command as mandatory. A host can use the command as a fast and reliable method to erase the media.

READ
The READ and WRITE commands are where a host accesses a device’s storage media. The host issues a READ command to request to read a block of data from the device’s storage media. In the command block, the LOGICAL BLOCK ADDRESS field specifies the LBA of the first requested block, and the TRANSFER LENGTH field contains the number of requested blocks.

There are five READ commands: READ(6), READ(10), READ(12), READ(16), and READ(32). The commands vary in the sizes of the logical- block-address and transfer-length fields and in the quantity and type of status and control information included in the command block. READ(6) and READ(10) are mandatory for SBC devices. The specification recommends migrating all code from READ(6) to READ(10), but a host might still attempt to use READ(6). The Windows USB mass-storage driver uses READ(10).

On receiving a READ(10) command, a device should send the contents of the requested blocks to the host in the data-transport phase. The device doesn’t have to know or care what is in the requested blocks. All the device needs is a block number and the number of blocks to return.

The MSDReadHandler function reads the block address and the number of bytes to transfer specified in the CBW, handles any detected errors, sets fields on the CSW, and calls the MSDDataIn function from Chapter 3 to send the requested data.

The MSDReadHandler function uses the variable gblNumBLKS, which contains the number of blocks in the volume. The section describing the READ CAPACITY command later in this chapter shows how to obtain the value.

byte *ptrNextData;
void MSDReadHandler()
{
byte Flags;
word i;
DWORD LBA;
dword sectorNumber;
SDC_Error status;
WORD TransferLength;
/// The command block stores the MSB first. Device firmware stores the LSB first.
// The starting LBA to read is in bytes 2-5 of the command block.
LBA.v[3] = gblCBW.CBWCB[2];
LBA.v[2] = gblCBW.CBWCB[3];
LBA.v[1] = gblCBW.CBWCB[4];
LBA.v[0] = gblCBW.CBWCB[5];
// The number of blocks to transfer is in bytes 7 and 8 of the CBW.
TransferLength.v[1] = gblCBW.CBWCB[7];
TransferLength.v[0] = gblCBW.CBWCB[8];
// The data-transport phase is device to host.
Flags = gblCBW.CBWCB[1];
// Set default values in the CSW.
msd_csw.bCSWStatus = 0×0; // Success.
msd_csw.dCSWDataResidue = 0×0;
if (LBA._dword + TransferLength._word > gblNumBLKS._dword) {
// The requested blocks extend beyond the available blocks in the media.
// Set bCSWStatus to “command failed.”
// Store sense data to describe the error.
msd_csw.bCSWStatus = 0×01;
gblSenseData.SenseKey = S_ILLEGAL_REQUEST;
gblSenseData.ASC = ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
gblSenseData.ASCQ = ASCQ_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;

} else {
// Read blocks from the media and send the contents to the USB host
// until TransferLength = 0.
while (TransferLength._word > 0) {
// Decrement the number of blocks remaining.
TransferLength._word–;
// Copy the specified block’s data into msd_buffer.
status = SectorRead(LBA._dword, (byte*)&msd_buffer[0]);
// Increment the LBA.
LBA._dword++;
if (status == sdcValid) {
// The sector-read operation succeeded.
// Prepare to send 512 bytes to the USB host.
// Set fields in the CSW.
msd_csw.bCSWStatus = 0×00;
msd_csw.dCSWDataResidue = 0×200; // 512 bytes
// The next block to read begins where this one ended.
ptrNextData = (byte *)&msd_buffer[0];
while (msd_csw.dCSWDataResidue > 0)
// The MSDDataIn function sends the data to the USB host.
// dCSWDataResidue is decremented as the data is sent.
// Continue until dCSWDataResidue = 0.

MSDDataIn();
// Reset dCSWDataResidue.
msd_csw.dCSWDataResidue = 0×0;
} else {
// The command failed.
// Store sense data to describe the error.
msd_csw.bCSWStatus = 0×01;
gblSenseData.SenseKey = S_MEDIUM_ERROR;
gblSenseData.ASC = ASC_UNRECOVERED_READ_ERROR;
gblSenseData.ASCQ = ASCQ_UNRECOEVERED_READ_ERROR;
// Don’t send any more data.
msd_csw.dCSWDataResidue = 0×0;
break;
}
} // End transfer length > 0
} // End transfer length OK
}

Random Posts

No comments yet

Leave a Reply

You must be logged in to post a comment.