1 /* 2 * Testing block device, wraps filebd and rambd while providing a bunch 3 * of hooks for testing littlefs in various conditions. 4 * 5 * Copyright (c) 2022, The littlefs authors. 6 * Copyright (c) 2017, Arm Limited. All rights reserved. 7 * SPDX-License-Identifier: BSD-3-Clause 8 */ 9 #ifndef LFS_TESTBD_H 10 #define LFS_TESTBD_H 11 12 #include "lfs.h" 13 #include "lfs_util.h" 14 #include "bd/lfs_rambd.h" 15 #include "bd/lfs_filebd.h" 16 17 #ifdef __cplusplus 18 extern "C" 19 { 20 #endif 21 22 23 // Block device specific tracing 24 #ifdef LFS_TESTBD_YES_TRACE 25 #define LFS_TESTBD_TRACE(...) LFS_TRACE(__VA_ARGS__) 26 #else 27 #define LFS_TESTBD_TRACE(...) 28 #endif 29 30 // Mode determining how "bad blocks" behave during testing. This simulates 31 // some real-world circumstances such as progs not sticking (prog-noop), 32 // a readonly disk (erase-noop), and ECC failures (read-error). 33 // 34 // Not that read-noop is not allowed. Read _must_ return a consistent (but 35 // may be arbitrary) value on every read. 36 enum lfs_testbd_badblock_behavior { 37 LFS_TESTBD_BADBLOCK_PROGERROR, 38 LFS_TESTBD_BADBLOCK_ERASEERROR, 39 LFS_TESTBD_BADBLOCK_READERROR, 40 LFS_TESTBD_BADBLOCK_PROGNOOP, 41 LFS_TESTBD_BADBLOCK_ERASENOOP, 42 }; 43 44 // Type for measuring wear 45 typedef uint32_t lfs_testbd_wear_t; 46 typedef int32_t lfs_testbd_swear_t; 47 48 // testbd config, this is required for testing 49 struct lfs_testbd_config { 50 // 8-bit erase value to use for simulating erases. -1 does not simulate 51 // erases, which can speed up testing by avoiding all the extra block-device 52 // operations to store the erase value. 53 int32_t erase_value; 54 55 // Number of erase cycles before a block becomes "bad". The exact behavior 56 // of bad blocks is controlled by the badblock_mode. 57 uint32_t erase_cycles; 58 59 // The mode determining how bad blocks fail 60 uint8_t badblock_behavior; 61 62 // Number of write operations (erase/prog) before forcefully killing 63 // the program with exit. Simulates power-loss. 0 disables. 64 uint32_t power_cycles; 65 66 // Optional buffer for RAM block device. 67 void *buffer; 68 69 // Optional buffer for wear 70 void *wear_buffer; 71 }; 72 73 // testbd state 74 typedef struct lfs_testbd { 75 union { 76 struct { 77 lfs_filebd_t bd; 78 struct lfs_filebd_config cfg; 79 } file; 80 struct { 81 lfs_rambd_t bd; 82 struct lfs_rambd_config cfg; 83 } ram; 84 } u; 85 86 bool persist; 87 uint32_t power_cycles; 88 lfs_testbd_wear_t *wear; 89 90 const struct lfs_testbd_config *cfg; 91 } lfs_testbd_t; 92 93 94 /// Block device API /// 95 96 // Create a test block device using the geometry in lfs_config 97 // 98 // Note that filebd is used if a path is provided, if path is NULL 99 // testbd will use rambd which can be much faster. 100 int lfs_testbd_create(const struct lfs_config *cfg, const char *path); 101 int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, 102 const struct lfs_testbd_config *bdcfg); 103 104 // Clean up memory associated with block device 105 int lfs_testbd_destroy(const struct lfs_config *cfg); 106 107 // Read a block 108 int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, 109 lfs_off_t off, void *buffer, lfs_size_t size); 110 111 // Program a block 112 // 113 // The block must have previously been erased. 114 int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, 115 lfs_off_t off, const void *buffer, lfs_size_t size); 116 117 // Erase a block 118 // 119 // A block must be erased before being programmed. The 120 // state of an erased block is undefined. 121 int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block); 122 123 // Sync the block device 124 int lfs_testbd_sync(const struct lfs_config *cfg); 125 126 127 /// Additional extended API for driving test features /// 128 129 // Get simulated wear on a given block 130 lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_config *cfg, 131 lfs_block_t block); 132 133 // Manually set simulated wear on a given block 134 int lfs_testbd_setwear(const struct lfs_config *cfg, 135 lfs_block_t block, lfs_testbd_wear_t wear); 136 137 138 #ifdef __cplusplus 139 } /* extern "C" */ 140 #endif 141 142 #endif 143