| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_DEVICES_BLOCK_DRIVERS_FTL_TESTS_NDM_RAM_DRIVER_H_ |
| #define SRC_DEVICES_BLOCK_DRIVERS_FTL_TESTS_NDM_RAM_DRIVER_H_ |
| |
| #include <inttypes.h> |
| #include <lib/ftl/ndm-driver.h> |
| #include <zircon/types.h> |
| |
| #include <cstdint> |
| #include <limits> |
| |
| #include <fbl/array.h> |
| |
| struct TestOptions { |
| static constexpr TestOptions NoEccErrors() { |
| TestOptions options = {}; |
| options.ecc_error_interval = std::numeric_limits<int>::max(); |
| options.save_config_data = false; |
| return options; |
| } |
| |
| // Controls simulation of ECC errors. |
| int ecc_error_interval = 900; |
| |
| // Controls simulation of bad block sequence. |
| int bad_block_interval = 50; |
| |
| // Controls the size of the sequence of operations that will run |
| // into a bad block. |
| int bad_block_burst = 1; |
| |
| // Makes only half of the space visible. |
| bool use_half_size = false; |
| |
| // Save options on the partition info. |
| bool save_config_data = true; |
| |
| // Delay before power failure kicks in. |
| int power_failure_delay = -1; |
| }; |
| |
| // Ram-backed driver for testing purposes. |
| class NdmRamDriver final : public ftl::NdmBaseDriver { |
| public: |
| explicit NdmRamDriver(const ftl::VolumeOptions& options) : NdmRamDriver(options, {}) {} |
| NdmRamDriver(const ftl::VolumeOptions& options, const TestOptions& test_options) |
| : NdmBaseDriver(ftl::DefaultLogger()), options_(options), test_options_(test_options) {} |
| ~NdmRamDriver() final = default; |
| |
| // Extends the visible volume to the whole size of the storage. |
| bool DoubleSize(); |
| |
| void save_config_data(bool value) { test_options_.save_config_data = value; } |
| |
| void set_options(const ftl::VolumeOptions& options) { options_ = options; } |
| void set_max_bad_blocks(uint32_t value) { options_.max_bad_blocks = value; } |
| uint32_t num_bad_blocks() const { return num_bad_blocks_; } |
| |
| void SetPowerFailureDelay(int delay) { |
| test_options_.power_failure_delay = delay; |
| power_failure_delay_ = 0; |
| power_failure_triggered_ = false; |
| } |
| |
| // NdmDriver interface: |
| const char* Init() final; |
| const char* Attach(const ftl::Volume* ftl_volume) final; |
| bool Detach() final; |
| int NandRead(uint32_t start_page, uint32_t page_count, void* page_buffer, void* oob_buffer) final; |
| int NandWrite(uint32_t start_page, uint32_t page_count, const void* page_buffer, |
| const void* oob_buffer) final; |
| int NandErase(uint32_t page_num) final; |
| int IsBadBlock(uint32_t page_num) final; |
| bool IsEmptyPage(uint32_t page_num, const uint8_t* data, const uint8_t* spare) final; |
| uint32_t PageSize() final; |
| uint8_t SpareSize() final; |
| |
| private: |
| // Reads or Writes a single page. |
| int ReadPage(uint32_t page_num, uint8_t* data, uint8_t* spare); |
| int WritePage(uint32_t page_num, const uint8_t* data, const uint8_t* spare); |
| |
| // Returns true for a freshly minted bad block. |
| bool SimulateBadBlock(uint32_t page_num); |
| |
| // Returns true if a power failure should be triggered at this point. |
| bool ShouldTriggerPowerFailure(); |
| |
| // Triggers side-effects of a power failure. |
| void OnWritePowerFailure(uint64_t page_number, const uint8_t* data, const uint8_t* spare); |
| void OnErasePowerFailure(uint64_t page_number); |
| |
| // Access the main data and spare area for a given page. |
| uint8_t* MainData(uint32_t page_num); |
| uint8_t* SpareData(uint32_t page_num); |
| |
| // Access flags for a given page. |
| bool Written(uint32_t page_num); |
| bool FailEcc(uint32_t page_num); |
| bool BadBlock(uint32_t page_num); |
| void SetWritten(uint32_t page_num, bool value); |
| void SetFailEcc(uint32_t page_num, bool value); |
| void SetBadBlock(uint32_t page_num, bool value); |
| |
| uint32_t PagesPerBlock() const; |
| |
| fbl::Array<uint8_t> volume_; |
| fbl::Array<uint8_t> flags_; |
| ftl::VolumeOptions options_; |
| TestOptions test_options_; |
| |
| // Controls simulation of ECC errors. |
| int ecc_error_interval_ = 0; |
| |
| // Controls simulation of bad blocks. |
| int bad_block_interval_ = 0; |
| |
| // Marks that power failure happened. |
| bool power_failure_triggered_ = false; |
| |
| // Controls simulation of bad blocks. |
| int power_failure_delay_ = 0; |
| |
| uint32_t num_bad_blocks_ = 0; |
| }; |
| |
| #endif // SRC_DEVICES_BLOCK_DRIVERS_FTL_TESTS_NDM_RAM_DRIVER_H_ |