fix(nand-ftl): 传输失败不再误标坏块 + format 不再被脏缓存挡死(#79)
根因(真机定案,问题 #79):旧 dhara_nand_erase/prog() 把一切失败一律 mark_bad,而 mark_block_bad 每次**立即持久化**板级 BBT(不可撤销)—— 一次传输层/等忙抖动就把好块永久记成坏块。台架 129 个好块(1016–1142 连续段)被固化,journal prepare_head() 连续 8 次撞 is_bad → TOO_BAD → Cache flush FAIL → reformat 又被同一页挡住 → 整卷禁用、重启不恢复。 - 修复①:只有芯片明确回 E_FAIL/P_FAIL(状态位证据)才标坏; 传输/超时失败只报 DHARA_E_BAD_BLOCK 让 dhara 重试,不标坏 - 修复②:nand_ftl_format() 尽力刷一次脏缓存,失败即丢弃并继续 dhara_map_clear()(格式化语义本就是销毁映射;旧实现第一步返回, 恢复动作在同一页死锁,f_mkfs 全在旧映射上必失败) - C4 还债:新增跨调用失败类快照 nand_ftl_fault_get/clear(20 B, resume/读/刷/同步四点位记账);defaultTask 探针按类分流, BSP_ERR_NO_SPACE 跳过重格式化(容量问题不该用 mkfs 解) - 哨兵与诊断:init 解锁块保护(A0h)后补回读校验(与 B0h ECC 同族 缺口,实测本板 A0h=0,非本次根因,留作哨兵);gd5f_bbt_load() 合并后坏块数 > 出厂扫描时打「BBT after merge」,现场可区分 真坏与误标固化 - 测试:主机单测 149→178 全绿;新增 format 死锁(TC-NANDPORT-800.. 813b)、传输失败不标坏(207 语义翻转 + 208/505);牙齿检查过—— 把修复回退即见红 - 真机:恢复动作 A 重建 BBT 清除已固化误标(3/3 PASSED,BBT version=71);产品镜像复烧 [FS] FATFS mounted、配置出厂模板 落盘、0 条 flush FAIL——#79 真机闭环(旧卷内容随 map clear 作废,台架卷为可弃数据) - 文档:存储架构说明 §10.4 口径修正 + 新增 §10.4.1/§10.4.2(页级 失败升级链与误标持久化机理),存储维护与容量恢复 §2 补板级 BBT 独立持久化注记 + §2.1(动作 A 此前静默失效),登记簿 C4 销项 - Keil 0 错 0 警(Code=255552,与烧录验证镜像一致);doc-links 213 文档通过
This commit is contained in:
+45
-18
@@ -48,6 +48,7 @@
|
||||
#include "main.h"
|
||||
#include "ff.h"
|
||||
#include "nand_ftl.h"
|
||||
#include "bsp_err.h" /* BSP_ERR_NO_SPACE / BSP_ERR_CRC:卷健康探针按失败类分流(C4) */
|
||||
#include "net_cfg.h"
|
||||
#include "cfg_file.h"
|
||||
#include "run_par.h" /* 运行参数段落盘(「数据可信」这一项,配置引擎属主 = 本任务) */
|
||||
@@ -523,30 +524,56 @@ static FRESULT storage_bring_up(FATFS *fs) {
|
||||
FS_VOL_PROBE(hfr); /* 两击确认 */
|
||||
}
|
||||
if (hfr != FR_OK) {
|
||||
/* C4 消费点(2026-11-04,问题 #79):探针只拿到 FRESULT,失败类在
|
||||
* disk_read/disk_write 返回时就被 FatFs 契约抹掉了。这里把 FTL 留下的
|
||||
* 跨调用快照读出来,**先判"重格式化有没有意义"再决定动作**——
|
||||
* 这正是 存储架构说明 §10.4 那条一直只写在文档里、没有消费者的判据。
|
||||
*
|
||||
* 为什么必须先判:BSP_ERR_NO_SPACE 是 journal/映射层块池见底(介质健康),
|
||||
* 重格式化只会把问题推回去(文档原文);而 BSP_ERR_CRC 才是"页级太坏,
|
||||
* 换页/reformat 可能救"。两类都走 reformat 的话,块池见底会被反复擦盘。 */
|
||||
nand_ftl_fault_t fault;
|
||||
|
||||
nand_ftl_fault_get(&fault);
|
||||
if (fault.active != 0u) {
|
||||
DBG_ERROR("[FS] probe failed (fr=%d), FTL last fault: op=%u class=%ld lpn=%lu count=%lu",
|
||||
(int)hfr, (unsigned)fault.op, (long)fault.cls,
|
||||
(unsigned long)fault.lpn, (unsigned long)fault.count);
|
||||
}
|
||||
|
||||
/* ⚠ FR_INVALID_NAME 绝不可入本集合:它是路径名语法错误(纯 RAM 判定、
|
||||
* 不碰盘),与卷健康无关(曾误入 → "无限重格式化"事故) */
|
||||
if (hfr == FR_DENIED || hfr == FR_INVALID_OBJECT ||
|
||||
hfr == FR_INT_ERR || hfr == FR_DISK_ERR ||
|
||||
hfr == FR_NO_FILE || hfr == FR_NO_PATH ||
|
||||
hfr == FR_NO_FILESYSTEM) {
|
||||
DBG_INFO("[FS] volume FAT invalid (fr=%d), reformatting...",
|
||||
(int)hfr);
|
||||
f_mount(NULL, "", 0);
|
||||
/* 格式化前清空 FTL map 树(同首启路径:新卷从空树写起) */
|
||||
(void)nand_ftl_format();
|
||||
{
|
||||
static uint8_t fs_work2[FF_MAX_SS];
|
||||
MKFS_PARM opts2 = { FM_FAT32, 0, 0, 0, 0 };
|
||||
fr = f_mkfs("", &opts2, fs_work2, sizeof(fs_work2));
|
||||
if (fr == FR_OK) {
|
||||
fr = f_mount(fs, "", 1);
|
||||
}
|
||||
}
|
||||
if (fr == FR_OK) {
|
||||
DBG_INFO("[FS] volume reformatted OK");
|
||||
/* 按失败类分流:块池见底 ≠ 介质坏。前者擦卷救不回来,只上报
|
||||
* (后续应走容量恢复,见 存储维护与容量恢复.md),后者才 reformat。 */
|
||||
if ((fault.active != 0u) && (fault.cls == (int32_t)BSP_ERR_NO_SPACE)) {
|
||||
DBG_ERROR("[FS] volume probe failed: FTL out of space, "
|
||||
"reformat skipped (needs capacity recovery, not mkfs)");
|
||||
syslog_post(SYSLOG_SELFTEST, "storage full");
|
||||
fr = FR_INT_ERR;
|
||||
} else {
|
||||
DBG_ERROR("[FS] volume repair failed (fr=%d)", (int)fr);
|
||||
syslog_post(SYSLOG_SELFTEST, "storage fault");
|
||||
DBG_INFO("[FS] volume FAT invalid (fr=%d), reformatting...",
|
||||
(int)hfr);
|
||||
f_mount(NULL, "", 0);
|
||||
/* 格式化前清空 FTL map 树(同首启路径:新卷从空树写起) */
|
||||
(void)nand_ftl_format();
|
||||
{
|
||||
static uint8_t fs_work2[FF_MAX_SS];
|
||||
MKFS_PARM opts2 = { FM_FAT32, 0, 0, 0, 0 };
|
||||
fr = f_mkfs("", &opts2, fs_work2, sizeof(fs_work2));
|
||||
if (fr == FR_OK) {
|
||||
fr = f_mount(fs, "", 1);
|
||||
}
|
||||
}
|
||||
if (fr == FR_OK) {
|
||||
DBG_INFO("[FS] volume reformatted OK");
|
||||
} else {
|
||||
DBG_ERROR("[FS] volume repair failed (fr=%d)", (int)fr);
|
||||
syslog_post(SYSLOG_SELFTEST, "storage fault");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* 其余错误(写保护/卷锁/参数类)不重格式化——只上报,
|
||||
@@ -685,7 +712,7 @@ static void wave_store_drain(void) {
|
||||
}
|
||||
}
|
||||
if ((why == NULL) && (s_wscan_done == 0u)) {
|
||||
FRESULT rr;
|
||||
FRESULT rr = FR_OK;
|
||||
|
||||
fr = f_opendir(&s_wdir, WAVE_ST_DIR);
|
||||
if (fr == FR_OK) {
|
||||
|
||||
Reference in New Issue
Block a user