1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <inttypes.h> 8 9 struct ndm; 10 11 namespace ftl { 12 13 class Volume; 14 15 // Return values expected by NDM from the nand driver. 16 // See ndm-man-20150.pdf for the complete low level API specification: 17 constexpr int kNdmOk = 0; 18 constexpr int kNdmError = -1; 19 constexpr int kNdmUncorrectableEcc = -1; 20 constexpr int kNdmFatalError = -2; 21 constexpr int kNdmUnsafeEcc = 1; 22 constexpr int kTrue = 1; 23 constexpr int kFalse = 0; 24 25 // Options for a device to be created. All sizes are in bytes. 26 struct VolumeOptions { 27 uint32_t num_blocks; 28 uint32_t max_bad_blocks; 29 uint32_t block_size; 30 uint32_t page_size; 31 uint32_t eb_size; // Extra bytes, a.k.a. OOB. 32 uint32_t flags; 33 }; 34 35 // Encapsulates the lower layer TargetFtl-Ndm driver. 36 class NdmDriver { 37 public: ~NdmDriver()38 virtual ~NdmDriver() {} 39 40 // Performs driver initialization. Returns an error string, or nullptr on 41 // success. 42 virtual const char* Init() = 0; 43 44 // Creates a new volume. Note that multiple volumes are not supported. 45 // |ftl_volume| (if provided) will be notified with the volume details. 46 // Returns an error string, or nullptr on success. 47 virtual const char* Attach(const Volume* ftl_volume) = 0; 48 49 // Destroy the volume created with Attach(). Returns true on success. 50 virtual bool Detach() = 0; 51 52 // Reads |page_count| pages starting at |start_page|, placing the results on 53 // |page_buffer| and |oob_buffer|. Either pointer can be nullptr if that 54 // part is not desired. 55 // Returns kNdmOk, kNdmUncorrectableEcc, kNdmFatalError or kNdmUnsafeEcc. 56 virtual int NandRead(uint32_t start_page, uint32_t page_count, void* page_buffer, 57 void* oob_buffer) = 0; 58 59 // Writes |page_count| pages starting at |start_page|, using the data from 60 // |page_buffer| and |oob_buffer|. 61 // Returns kNdmOk, kNdmError or kNdmFatalError. kNdmError triggers marking 62 // the block as bad. 63 virtual int NandWrite(uint32_t start_page, uint32_t page_count, const void* page_buffer, 64 const void* oob_buffer) = 0; 65 66 // Erases the block containing |page_num|. 67 // Returns kNdmOk or kNdmError. kNdmError triggers marking the block as bad. 68 virtual int NandErase(uint32_t page_num) = 0; 69 70 // Returns whether the block containing |page_num| was factory-marked as bad. 71 // Returns kTrue, kFalse or kNdmError. 72 virtual int IsBadBlock(uint32_t page_num) = 0; 73 74 // Returns whether a given page is empty or not. |data| and |spare| store 75 // the contents of the page. 76 virtual bool IsEmptyPage(uint32_t page_num, const uint8_t* data, const uint8_t* spare) = 0; 77 }; 78 79 // Base functionality for a driver implementation. 80 class NdmBaseDriver : public NdmDriver { 81 public: NdmBaseDriver()82 NdmBaseDriver() {} 83 virtual ~NdmBaseDriver(); 84 85 // Creates the underlying NDM volume, with the provided parameters. 86 const char* CreateNdmVolume(const Volume* ftl_volume, const VolumeOptions& options); 87 88 // Deletes the underlying NDM volume. 89 bool RemoveNdmVolume(); 90 91 // Inspects |data_len| bytes from |data| and |spare_len| bytes from |spare| 92 // looking for a typical empty (erased) page. Returns true if all bits are 1. 93 bool IsEmptyPageImpl(const uint8_t* data, uint32_t data_len, const uint8_t* spare, 94 uint32_t spare_len) const; 95 96 private: 97 ndm* ndm_ = nullptr; 98 }; 99 100 // Performs global module initialization. This is exposed to support unit tests, 101 // and while calling this function multiple times is supported, racing calls are 102 // not (or more generally, calling this from multiple threads). 103 // If multiple simultaneous tests from the same test instance ever becomes a 104 // thing, this should be called from testing::Environment and not from each 105 // test case. 106 bool InitModules(); 107 108 } // namespace ftl 109