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