/** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features * and capabilities to the host. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with * * \return Boolean true if the command completed successfully, false otherwise. */ static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) { uint16_t AllocationLength = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[3]); uint16_t BytesTransferred = MIN(AllocationLength, sizeof(InquiryData)); /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */ if ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]) { /* Optional but unsupported bits set - update the SENSE key and fail the request */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); return false; } Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NULL); /* Pad out remaining bytes with 0x00 */ Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL); /* Finalize the stream transfer to send the last packet */ Endpoint_ClearIN(); /* Succeed the command and update the bytes transferred counter */ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred; return true; }
/** Command processing for an issued SCSI SEND DIAGNOSTIC command. This command performs a quick check of the Dataflash ICs on the * board, and indicates if they are present and functioning correctly. Only the Self-Test portion of the diagnostic command is * supported. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with */ static void SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) { /* Check to see if the SELF TEST bit is not set */ if (!(MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & (1 << 2))) { /* Only self-test supported - update SENSE key and fail the command */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); return; } /* Check to see if all attached Dataflash ICs are functional */ /* if (!(DataflashManager_CheckDataflashOperation())) { // Update SENSE key with a hardware error condition and return command fail SCSI_SET_SENSE(SCSI_SENSE_KEY_HARDWARE_ERROR, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER); return; } */ /* Succeed the command and update the bytes transferred counter */ MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0; }
/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address * and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual * reading and writing of the data. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with * \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE) * * \return Boolean true if the command completed successfully, false otherwise. */ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, const bool IsDataRead) { uint32_t BlockAddress; uint16_t TotalBlocks; /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */ BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]); /* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */ TotalBlocks = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]); /* Check if the block address is outside the maximum allowable value for the LUN */ if (BlockAddress >= VIRTUAL_MEMORY_BLOCKS) { /* Block address is invalid, update SENSE key and return command fail */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); return false; } /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ if (IsDataRead == DATA_READ) DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); else DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); /* Update the bytes transferred counter and succeed the command */ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE); return true; }
/** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features * and capabilities to the host. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with */ static void SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* MSInterfaceInfo) { uint16_t AllocationLength = (((uint16_t)MSInterfaceInfo->State.CommandBlock.SCSICommandData[3] << 8) | MSInterfaceInfo->State.CommandBlock.SCSICommandData[4]); uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? AllocationLength : sizeof(InquiryData); /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */ if ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]) { /* Optional but unsupported bits set - update the SENSE key and fail the request */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); return; } Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NO_STREAM_CALLBACK); uint8_t PadBytes[AllocationLength - BytesTransferred]; /* Pad out remaining bytes with 0x00 */ Endpoint_Write_Stream_LE(&PadBytes, (AllocationLength - BytesTransferred), NO_STREAM_CALLBACK); /* Finalize the stream transfer to send the last packet */ Endpoint_ClearIN(); /* Succeed the command and update the bytes transferred counter */ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred; }
/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address * and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual * reading and writing of the data. * * \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE) */ static void SCSI_Command_ReadWrite_10(const bool IsDataRead) { uint32_t BlockAddress = SwapEndian_32(*(uint32_t*)&CommandBlock.SCSICommandData[2]); uint16_t TotalBlocks = SwapEndian_16(*(uint16_t*)&CommandBlock.SCSICommandData[7]); /* Check if the block address is outside the maximum allowable value for the LUN */ if (BlockAddress >= LUN_MEDIA_BLOCKS) { /* Block address is invalid, update SENSE key and return command fail */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); return; } #if (TOTAL_LUNS > 1) /* Adjust the given block address to the real media address based on the selected LUN */ BlockAddress += ((uint32_t)CommandBlock.LUN * LUN_MEDIA_BLOCKS); #endif /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ if (IsDataRead == DATA_READ) DataflashManager_ReadBlocks(BlockAddress, TotalBlocks); else DataflashManager_WriteBlocks(BlockAddress, TotalBlocks); /* Update the bytes transferred counter and succeed the command */ CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE); }
/** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features * and capabilities to the host. */ static void SCSI_Command_Inquiry(void) { uint16_t AllocationLength = SwapEndian_16(*(uint16_t*)&CommandBlock.SCSICommandData[3]); uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? AllocationLength : sizeof(InquiryData); /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */ if ((CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || CommandBlock.SCSICommandData[2]) { /* Optional but unsupported bits set - update the SENSE key and fail the request */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); return; } /* Write the INQUIRY data to the endpoint */ Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, StreamCallback_AbortOnMassStoreReset); uint8_t PadBytes[AllocationLength - BytesTransferred]; /* Pad out remaining bytes with 0x00 */ Endpoint_Write_Stream_LE(&PadBytes, sizeof(PadBytes), StreamCallback_AbortOnMassStoreReset); /* Finalize the stream transfer to send the last packet */ Endpoint_ClearIN(); /* Succeed the command and update the bytes transferred counter */ CommandBlock.DataTransferLength -= BytesTransferred; }
/** Main routine to process the SCSI command located in the Command Block Wrapper read from the host. This dispatches * to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns * a command failure due to a ILLEGAL REQUEST. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with */ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* MSInterfaceInfo) { /* Set initial sense data, before the requested command is processed */ SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER); /* Run the appropriate SCSI command hander function based on the passed command */ switch (MSInterfaceInfo->State.CommandBlock.SCSICommandData[0]) { case SCSI_CMD_INQUIRY: SCSI_Command_Inquiry(MSInterfaceInfo); break; case SCSI_CMD_REQUEST_SENSE: SCSI_Command_Request_Sense(MSInterfaceInfo); break; case SCSI_CMD_READ_CAPACITY_10: SCSI_Command_Read_Capacity_10(MSInterfaceInfo); break; case SCSI_CMD_SEND_DIAGNOSTIC: SCSI_Command_Send_Diagnostic(MSInterfaceInfo); break; case SCSI_CMD_WRITE_10: SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE); break; case SCSI_CMD_READ_10: SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ); break; case SCSI_CMD_TEST_UNIT_READY: case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: case SCSI_CMD_VERIFY_10: /* These commands should just succeed, no handling required */ MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0; break; default: /* Update the SENSE key to reflect the invalid command */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_COMMAND, SCSI_ASENSEQ_NO_QUALIFIER); break; } return (SenseData.SenseKey == SCSI_SENSE_KEY_GOOD); }
/** Command processing for an issued SCSI SEND DIAGNOSTIC command. This command performs a quick check of the Dataflash ICs on the * board, and indicates if they are present and functioning correctly. Only the Self-Test portion of the diagnostic command is * supported. */ static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t *const MSInterfaceInfo) { /* Check to see if the SELF TEST bit is not set */ if (!(MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & (1 << 2))) { /* Only self-test supported - update SENSE key and fail the command */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); return false; } /* Succeed the command and update the bytes transferred counter */ MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0; return true; }
/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address * and total number of blocks to process, then calls the appropriate low-level dataflash routine to handle the actual * reading and writing of the data. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with * \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE) * * \return Boolean true if the command completed successfully, false otherwise. */ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const bool IsDataRead) { uint32_t BlockAddress; uint16_t TotalBlocks; /* Load in the 32-bit block address (SCSI uses big-endian, so have to do it byte-by-byte) */ ((uint8_t*)&BlockAddress)[3] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]; ((uint8_t*)&BlockAddress)[2] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[3]; ((uint8_t*)&BlockAddress)[1] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4]; ((uint8_t*)&BlockAddress)[0] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[5]; /* Load in the 16-bit total blocks (SCSI uses big-endian, so have to do it byte-by-byte) */ ((uint8_t*)&TotalBlocks)[1] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]; ((uint8_t*)&TotalBlocks)[0] = MSInterfaceInfo->State.CommandBlock.SCSICommandData[8]; /* Check if the block address is outside the maximum allowable value for the LUN */ if (BlockAddress >= LUN_MEDIA_BLOCKS) { /* Block address is invalid, update SENSE key and return command fail */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); return false; } #if (TOTAL_LUNS > 1) /* Adjust the given block address to the real media address based on the selected LUN */ BlockAddress += ((uint32_t)MSInterfaceInfo->State.CommandBlock.LUN * LUN_MEDIA_BLOCKS); #endif /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ if (IsDataRead == DATA_READ) DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); else DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); /* Update the bytes transferred counter and succeed the command */ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE); return true; }
/** Main routine to process the SCSI command located in the Command Block Wrapper read from the host. This dispatches * to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns * a command failure due to a ILLEGAL REQUEST. */ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t *const MSInterfaceInfo) { bool CommandSuccess = false; //xprintf("\nSCSI%d", MSInterfaceInfo->State.CommandBlock.SCSICommandData[0]); /* Run the appropriate SCSI command hander function based on the passed command */ switch (MSInterfaceInfo->State.CommandBlock.SCSICommandData[0]) { case SCSI_CMD_INQUIRY: CommandSuccess = SCSI_Command_Inquiry(MSInterfaceInfo); break; case SCSI_CMD_REQUEST_SENSE: CommandSuccess = SCSI_Command_Request_Sense(MSInterfaceInfo); break; case SCSI_CMD_READ_CAPACITY_10: CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo); break; case SCSI_CMD_SEND_DIAGNOSTIC: CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo); break; case SCSI_CMD_WRITE_10: CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE); break; case SCSI_CMD_READ_10: CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ); break; case SCSI_CMD_MODE_SENSE_6: CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo); break; case SCSI_CMD_TEST_UNIT_READY: case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: case SCSI_CMD_VERIFY_10: /* These commands should just succeed, no handling required */ CommandSuccess = true; MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0; break; default: /* Update the SENSE key to reflect the invalid command */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_COMMAND, SCSI_ASENSEQ_NO_QUALIFIER); break; } /* Check if command was successfully processed */ if (CommandSuccess) { SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER); return true; } return false; }
/* FAT_BOOT_RECORD fatBootData = { .bootstrap = {0xeb, 0x3c, 0x90}, .OEM = "OpenPCR ", .iBytesPerSector = 512, .iSectorsPerCluster = 1, .iReservedSectors = 1, .iFATs = 2, .iRootEntries = 16, .iTotalSectors = 128, .iMediaDescr = 0xf0, .iSectorsPerFAT = 1, .iSectorsPerTrack = 0, .iHeads = 0, .iHiddenSectors = 0, .iTotalSectorsEx = 0, .iLogicDriveNumber = 0, .extSignature = 0x29, .serialNumber = USE_INTERNAL_SERIAL, .volumeLabel = "No Name ", .fatName = "FAT16 ", .exeCode = "", .exeEndMarker = {0x55, 0xaa} }; FAT_BOOT_RECORD fatBootData = { .bootstrap = {0xeb, 0x3c, 0x90}, .OEM = "OpenPCR", .iBytesPerSector = 512, .iSectorsPerCluster = 1, .iReservedSectors = 1, .iFATs = 2, .iRootEntries = 512, .iTotalSectors = 128, .iMediaDescr = 0xf0, .iSectorsPerFAT = 64, .iSectorsPerTrack = 0, .iHeads = 0, .iHiddenSectors = 0, .iTotalSectorsEx = 0, .iLogicDriveNumber = 0, .extSignature = 0x29, .serialNumber = USE_INTERNAL_SERIAL, .volumeLabel = {'N', 'o', ' ', 'N', 'a', 'm', 'e'}, .fatName = {'F', 'A', 'T', '1', '6'}, .exeCode = {}, .exeEndMarker = {0x55, 0xaa} }; */ static void SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, const bool IsDataRead) { uint32_t BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]); uint16_t TotalBlocks = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]); /* Check if the block address is outside the maximum allowable value for the LUN */ if (BlockAddress >= LUN_MEDIA_BLOCKS) { // Block address is invalid, update SENSE key and return command fail SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); return; } #if (TOTAL_LUNS > 1) /* Adjust the given block address to the real media address based on the selected LUN */ BlockAddress += ((uint32_t)MSInterfaceInfo->State.CommandBlock.LUN * LUN_MEDIA_BLOCKS); #endif #if 0 /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ if (IsDataRead == DATA_READ){ int block_index = 0; while (TotalBlocks){ if (BlockAddress == 0){ //BOOT Record Endpoint_Write_Stream_LE(&fatBootData, sizeof(FAT_BOOT_RECORD), NO_STREAM_CALLBACK); } else if (BlockAddress == 1 || BlockAddress == 2){ //FAT TABLE 1 and 2 uint16_t firstBlock = 0xfff0; uint16_t secondBlock = 0xffff; Endpoint_Write_Stream_BE(&firstBlock, sizeof(firstBlock), NO_STREAM_CALLBACK); Endpoint_Write_Stream_BE(&secondBlock, sizeof(secondBlock), NO_STREAM_CALLBACK); for (block_index=4; block_index<VIRTUAL_MEMORY_BLOCK_SIZE; block_index++){ Endpoint_Write_Byte(0x00); } } else{ for (block_index=0; block_index<VIRTUAL_MEMORY_BLOCK_SIZE; block_index++){ Endpoint_Write_Byte(0x00); } } BlockAddress++; TotalBlocks--; } } Endpoint_ClearIN(); #endif /* if (IsDataRead == DATA_READ) DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); else DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); */ /* Update the bytes transferred counter and succeed the command */ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE); }
/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address * and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual * reading and writing of the data. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with * \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE) * * \return Boolean true if the command completed successfully, false otherwise. */ static bool SCSI_Command_ReadWrite_10 (USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, const bool IsDataRead) { uint32_t BlockAddress; uint16_t TotalBlocks; //uint8_t buffer[VIRTUAL_MEMORY_BLOCK_SIZE]; /* Check if the disk is write protected or not */ if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY) { /* Block address is invalid, update SENSE key and return command fail */ SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT, SCSI_ASENSE_WRITE_PROTECTED, SCSI_ASENSEQ_NO_QUALIFIER); return false; } /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */ //BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]); BlockAddress = (MSInterfaceInfo->State.CommandBlock.SCSICommandData[2] << 24) + (MSInterfaceInfo->State.CommandBlock.SCSICommandData[3] << 16) + (MSInterfaceInfo->State.CommandBlock.SCSICommandData[4] << 8) + MSInterfaceInfo->State.CommandBlock.SCSICommandData[5]; /* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */ //TotalBlocks = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]); TotalBlocks = (MSInterfaceInfo->State.CommandBlock.SCSICommandData[7] << 8) + MSInterfaceInfo->State.CommandBlock.SCSICommandData[8]; /* Check if the block address is outside the maximum allowable value for the LUN */ if (BlockAddress >= LUN_MEDIA_BLOCKS) { /* Block address is invalid, update SENSE key and return command fail */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); return false; } #if (TOTAL_LUNS > 1) /* Adjust the given block address to the real media address based on the selected LUN */ BlockAddress += ((uint32_t)MSInterfaceInfo->State.CommandBlock.LUN * LUN_MEDIA_BLOCKS); #endif /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ #if 0 if (IsDataRead == DATA_READ) { int i; for(i=0;i<TotalBlocks;i++) { while(!Endpoint_IsReadWriteAllowed()); MassStorage_Read(((BlockAddress+i)*VIRTUAL_MEMORY_BLOCK_SIZE), buffer, VIRTUAL_MEMORY_BLOCK_SIZE); Endpoint_Write_Stream_LE(buffer, VIRTUAL_MEMORY_BLOCK_SIZE,NULL); Endpoint_ClearIN(); } } else { int i; for(i=0;i<TotalBlocks;i++) { while(!Endpoint_IsReadWriteAllowed()); Endpoint_Read_Stream_LE(buffer,VIRTUAL_MEMORY_BLOCK_SIZE,NULL); Endpoint_ClearOUT(); MassStorage_Write((BlockAddress+i)*VIRTUAL_MEMORY_BLOCK_SIZE,buffer, VIRTUAL_MEMORY_BLOCK_SIZE); } } #else uint32_t startaddr; uint16_t blocks, dummyblocks; startaddr = MassStorage_GetAddressInImage(BlockAddress, TotalBlocks, &blocks); if (blocks == 0) dummyblocks = TotalBlocks; else if (blocks < TotalBlocks) dummyblocks = TotalBlocks - blocks; else dummyblocks = 0; Endpoint_Streaming((uint8_t*) startaddr, VIRTUAL_MEMORY_BLOCK_SIZE, blocks, dummyblocks); #endif /* Update the bytes transferred counter and succeed the command */ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t) TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE); return true; }