diff --git a/Drivers/BSP/GD5F2GQ5UE/nand_ftl.c b/Drivers/BSP/GD5F2GQ5UE/nand_ftl.c index 9d281bfd..0702e20c 100644 --- a/Drivers/BSP/GD5F2GQ5UE/nand_ftl.c +++ b/Drivers/BSP/GD5F2GQ5UE/nand_ftl.c @@ -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(); +}