FTL诊断增强:resume前裸NAND checkpoint扫描+header十六进制转储(定位编程落盘问题)

This commit is contained in:
2026-09-20 04:25:41 +08:00
parent 7a72aea4e5
commit f03a3b6633
+46 -8
View File
@@ -56,6 +56,7 @@ static uint8_t s_initialized;
static int ftl_flush_cache(void);
static int ftl_read_page(dhara_sector_t lpn);
static void ftl_scan_checks_raw(void);
/* SPI 原语从 gd5f2gq5ue.h 获取 */
@@ -205,6 +206,12 @@ DSTATUS disk_initialize(BYTE pdrv) {
dhara_map_init(&s_map, &s_nand, s_page_buf, 4);
/* 诊断:resume 前的裸 NAND checkpoint 扫描(复位后地面真值,
* 不经 FTL 缓存)——判定上一开机的 checkpoint 页是否真正写入芯片 */
DBG_INFO("Pre-resume raw check scan start: blocks=%lu",
(unsigned long)s_nand.num_blocks);
ftl_scan_checks_raw();
memset(s_cache_buf, 0, FTL_PAGE_SIZE);
s_cached_lpn = (dhara_sector_t)-1; /* -1 表示缓存未加载;LPN 0 合法,不能用 0 作哨兵 */
s_cache_dirty = 0;
@@ -421,9 +428,34 @@ void nand_ftl_log_state(const char *tag)
(unsigned long)dhara_map_size(&s_map));
}
/* 打印某块 checkpoint 页的 16 字节 header(magic/epoch/tail/bb),
* 用于区分"未落盘(全FF)"/"编程失败(花)"/"完整" 三种状态 */
static void ftl_dump_checkheader(uint32_t blk)
{
uint8_t hdr[16];
const uint32_t pg = ftl_phy_page((blk << s_nand.log2_ppb) |
((1u << s_map.journal.log2_ppc) - 1u));
if (gd5f_page_read(pg) != GD5F_OK) {
DBG_INFO("check hdr blk %lu: read fail", (unsigned long)blk);
return;
}
gd5f_read_from_cache(0, hdr, sizeof(hdr));
DBG_INFO("check hdr blk %lu: %02X %02X %02X %02X %02X %02X %02X %02X "
"%02X %02X %02X %02X %02X %02X %02X %02X",
(unsigned long)blk,
(unsigned int)hdr[0], (unsigned int)hdr[1], (unsigned int)hdr[2],
(unsigned int)hdr[3], (unsigned int)hdr[4], (unsigned int)hdr[5],
(unsigned int)hdr[6], (unsigned int)hdr[7],
(unsigned int)hdr[8], (unsigned int)hdr[9], (unsigned int)hdr[10],
(unsigned int)hdr[11], (unsigned int)hdr[12], (unsigned int)hdr[13],
(unsigned int)hdr[14], (unsigned int)hdr[15]);
}
/* 全扫每块首组 checkpoint 页(magic+epoch),打印连续区段分布,
* 用于识别 journal 环上的 epoch 分界与空洞 */
void nand_ftl_scan_checks(void)
* 用于识别 journal 环上的 epoch 分界与空洞。
* 裸读(gd5f 页读),不受 FTL 缓存影响 = NAND 真实内容。 */
static void ftl_scan_checks_raw(void)
{
uint32_t i;
uint8_t buf[8];
@@ -434,12 +466,6 @@ void nand_ftl_scan_checks(void)
uint8_t run_epoch = 0;
uint8_t run_open = 0;
if (!s_initialized) {
return;
}
DBG_INFO("check scan start: blocks=%lu", (unsigned long)s_nand.num_blocks);
for (i = 0; i < s_nand.num_blocks; i++) {
const uint32_t pg = ftl_phy_page((i << s_nand.log2_ppb) |
((1u << s_map.journal.log2_ppc) - 1u));
@@ -457,6 +483,7 @@ void nand_ftl_scan_checks(void)
DBG_INFO("check run: blk %lu..%lu epoch=%u (%lu blocks)",
(unsigned long)run_start, (unsigned long)run_prev,
(unsigned int)run_epoch, (unsigned long)run_len);
ftl_dump_checkheader(run_start);
}
run_start = i;
run_epoch = ep;
@@ -471,6 +498,17 @@ void nand_ftl_scan_checks(void)
DBG_INFO("check run: blk %lu..%lu epoch=%u (%lu blocks)",
(unsigned long)run_start, (unsigned long)run_prev,
(unsigned int)run_epoch, (unsigned long)run_len);
ftl_dump_checkheader(run_start);
}
DBG_INFO("check scan done: %lu checkpoint blocks", (unsigned long)total);
}
void nand_ftl_scan_checks(void)
{
if (!s_initialized) {
return;
}
DBG_INFO("check scan start: blocks=%lu", (unsigned long)s_nand.num_blocks);
ftl_scan_checks_raw();
}