| // 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_STORAGE_NAND_DRIVERS_NANDPART_AML_BAD_BLOCK_H_ |
| #define SRC_STORAGE_NAND_DRIVERS_NANDPART_AML_BAD_BLOCK_H_ |
| |
| #include <lib/zircon-internal/thread_annotations.h> |
| #include <lib/zx/vmar.h> |
| #include <lib/zx/vmo.h> |
| #include <stddef.h> |
| #include <zircon/types.h> |
| |
| #include <utility> |
| |
| #include <ddk/metadata/bad-block.h> |
| #include <fbl/array.h> |
| #include <fbl/ref_ptr.h> |
| |
| #include "bad-block.h" |
| |
| namespace nand { |
| |
| // Bad block implementation for NAND using Amlogic u-boot style bad block tables. |
| class AmlBadBlock : public BadBlock { |
| public: |
| struct OobMetadata { |
| // Identifier value. |
| uint32_t magic; |
| // Number of times the block has been programmed and erased. |
| int16_t program_erase_cycles; |
| // Iteration of the bad block table. Each time a new one is programmed, this |
| // should be incremented. Used to identify the newest copy. |
| uint16_t generation; |
| }; |
| |
| static zx_status_t Create(Config config, fbl::RefPtr<BadBlock>* out); |
| |
| zx_status_t GetBadBlockList(uint32_t first_block, uint32_t last_block, |
| fbl::Array<uint32_t>* bad_blocks) override; |
| zx_status_t MarkBlockBad(uint32_t block) override; |
| |
| private: |
| friend class fbl::RefPtr<AmlBadBlock>; |
| friend class fbl::internal::MakeRefCountedHelper<AmlBadBlock>; |
| |
| typedef uint8_t BlockStatus; |
| constexpr static BlockStatus kNandBlockGood = 0; |
| constexpr static BlockStatus kNandBlockBad = 1; |
| constexpr static BlockStatus kNandBlockFactoryBad = 2; |
| |
| constexpr static size_t kBlockListMax = 8; |
| |
| struct BlockListEntry { |
| uint32_t block; |
| int16_t program_erase_cycles; |
| bool valid; |
| }; |
| |
| AmlBadBlock(zx::vmo data_vmo, zx::vmo oob_vmo, fbl::Array<uint8_t> nand_op, Config config, |
| fuchsia_hardware_nand_Info nand_info, BlockStatus* table, uint32_t table_len, |
| OobMetadata* oob) |
| : BadBlock(std::move(data_vmo), std::move(oob_vmo), std::move(nand_op)), |
| config_(config.bad_block_config), |
| nand_proto_(config.nand_proto), |
| nand_(&nand_proto_), |
| nand_info_(nand_info), |
| block_entry_(nullptr), |
| page_(0), |
| generation_(0), |
| table_valid_(false), |
| oob_(oob), |
| bad_block_table_(table), |
| bad_block_table_len_(table_len) {} |
| |
| ~AmlBadBlock() override { |
| zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(oob_), sizeof(OobMetadata)); |
| zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(bad_block_table_), |
| bad_block_table_len_); |
| } |
| |
| // Synchronously erase a block. |
| zx_status_t EraseBlock(uint32_t block) TA_REQ(lock_); |
| |
| // Synchronously write |num_pages| into NAND. |
| zx_status_t WritePages(uint32_t nand_page, uint32_t num_pages) TA_REQ(lock_); |
| |
| // Synchronously read |num_pages| from NAND. |
| zx_status_t ReadPages(uint32_t nand_page, uint32_t num_pages) TA_REQ(lock_); |
| |
| // Looks for a valid block to write BBT to. |
| zx_status_t GetNewBlock(void) TA_REQ(lock_); |
| |
| // Writes in memory copy of BBT to the device. |
| zx_status_t WriteBadBlockTable(bool use_new_block) TA_REQ(lock_); |
| |
| // Finds BBT and reads it into memory from NAND. |
| zx_status_t FindBadBlockTable(void) TA_REQ(lock_); |
| |
| // Top level config. |
| const bad_block_config_t config_; |
| // Parent nand protocol implementation. |
| nand_protocol_t nand_proto_; |
| ddk::NandProtocolClient nand_; |
| const fuchsia_hardware_nand_Info nand_info_; |
| // Information about blocks which store BBT entries. |
| BlockListEntry block_list_[kBlockListMax]; |
| // Block with most recent valid BBT entry. |
| BlockListEntry* block_entry_; |
| // The first page for the last valid BBT entry in above block. |
| uint32_t page_; |
| // Generation ID of newest BBT entry. |
| uint16_t generation_; |
| // Whether the table is valid. |
| bool table_valid_; |
| // OOB metadata appended to end of table. Backed by oob_vmo. |
| OobMetadata* oob_; |
| // Copy of latest BBT. Each byte 1:1 maps to a block. Backed by data_vmo. |
| BlockStatus* bad_block_table_; |
| // Size of bad block table, rounded up to |nand_info_.page_size| multiple. |
| uint32_t bad_block_table_len_; |
| }; |
| } // namespace nand |
| |
| #endif // SRC_STORAGE_NAND_DRIVERS_NANDPART_AML_BAD_BLOCK_H_ |