/** 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 \c true if the command completed successfully, \c false otherwise. */ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, const bool IsDataRead) { uint32_t BlockAddress; uint16_t TotalBlocks; /* 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]); /* 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 >= MMC_MediaBlocks()) { /* 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 * MMC_MediaBlocks()); #endif /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ if (IsDataRead == DATA_READ) MMC_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks); else MMC_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; }
/** * @brief Reads data from EMMC block device manager * * @param[in] FPDConfig_p Flash device configuration of BDM * @param[in] Pos EMMC sector where reading should start. * @param[in] Length Number of sectors to read. * @param[in,out] FirstBad_p Not used for eMMC. * @param[out] Data_p Output buffer. * * @return ErrorCode_e Forwards the response from EMMC module. * * @remark This function should be called only from BDM module. */ ErrorCode_e Do_BDM_EMMC_Read(FPD_Config_t *const FPDConfig_p, uint32 Pos, uint32 Length, uint32 *FirstBad_p, uint8 *Data_p) { ErrorCode_e ReturnValue = E_GENERAL_FATAL_ERROR; t_mmc_error MMC_Error; void *TmpData_p = Data_p; IDENTIFIER_NOT_USED(FirstBad_p); // MMC interface requires uint32* for data, Data_p must be 32-bit aligned IS_ALIGNED((uint32)Data_p); // Jedec 84-A44 : Size < 2GB => byte addressing if (!FPDConfig_p->HC_Card) { Pos *= MMC_ADDRESS_MODE_FACTOR; } // Typecast on Data_p OK, alignment checked above MMC_Error = MMC_ReadBlocks(1, Pos, (uint32 *)TmpData_p, FPDConfig_p->PageSize, Length, FPDConfig_p->DeviceId); VERIFY(MMC_OK == MMC_Error, E_BDM_READ_FAILED); ReturnValue = E_SUCCESS; ErrorExit: return ReturnValue; }