ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

NAND Flash坏块管理指南:从物理原理到工程实践

NAND Flash坏块管理指南:从物理原理到工程实践 刚接手存储相关项目那会儿我最容易犯的错就是把NAND Flash当成普通存储介质来用——按扇区读写、理所当然地认为每一块都能用。直到产品在用户手里跑了三个月坏块静默增长图片文件东一块西一块损坏我才真正意识到NAND Flash的坏块管理不是可选项而是整个存储方案的生死线。这篇关于NandFlash存储原理与坏块管理的内容我想从物理结构讲到上层应用把那些数据手册里没写透、测试报告里看不出来的坑一个一个摊开来讲。这篇文章适合所有正在做嵌入式存储、SSD固件、U盘/存储卡方案、或者只是想在项目里用一颗裸NAND Flash的朋友。我会先讲清楚存储单元和坏块产生的底层原因再拆解坏块标记、扫描、管理策略最后给出一份来自真实项目的避坑清单。即便你是零基础跟着走一遍也会对NAND Flash的内部逻辑建立起完整的认知框架。1. 从浮栅晶体管开始NAND Flash是怎么存住数据的1.1 浮栅晶体管的“电荷囚笼”NAND Flash的最小存储单元就是一颗特殊的MOSFET普通MOSFET只有一个控制栅NAND Flash在控制栅和沟道之间额外塞了一层浮栅Floating Gate浮栅被一层高质量的氧化层完全包围跟周围绝缘。你可以把浮栅想象成一个四周密封的保险柜电子一旦被放进去没有外部电压帮忙就基本跑不出去。编程Program和擦除Erase的本质都是让电子穿过这道氧化层进入或离开浮栅。具体机制叫Fowler-Nordheim隧穿效应——在控制栅和衬底之间加一个足够强的电场氧化层厚度又很薄通常只有几纳米到十几纳米电子就有了量子隧穿的机会穿过绝缘层落进“保险柜”。读数据的时候外部给控制栅加一个参考电压然后看沟道能不能导通。如果浮栅里存了电子相当于晶体管阈值电压Vt抬高参考电压不足以让沟道导通读出“0”如果浮栅里没有电子阈值电压低沟道导通读出“1”。这里有个反直觉的点NAND Flash擦除后的状态是“1”编程后的状态是“0”所以出厂全片擦除状态下读出来全是0xFF。1.2 SLC到QLC同样一颗晶体管塞进更多比特单比特存储SLC只需要判断阈值电压高还是低但一颗晶体管完全可以做成多比特存储。厂家把阈值电压范围切分成多个区间每个区间对应一个二进制编码MLC2bit/cell4个阈值区间TLC3bit/cell8个阈值区间QLC4bit/cell16个阈值区间阈值区间越多相邻状态之间的电压间隔就越窄。电荷稍微漏一点、温度漂移一点、读取次数多了产生一点干扰都可能导致单元读出来落在错误的状态区间。所以高比特密度存储单元的P/E寿命急剧下降。我整理了一张对照表类型每单元比特数大致P/E寿命典型应用场景SLC15万~10万次工业控制、军工、高端嵌入式MLC23000~10000次消费级SSD、普通嵌入式TLC31000~3000次主流SSD、手机存储QLC4500~1000次大容量消费级SSD、归档存储这里要强调一个常见认知误区同样叫TLC不同制程、不同厂商的寿命差异巨大。3D TLC普遍比2D TLC耐用同样的P/E寿命数值在不同温度环境下表现也完全不同。选型时别只看单颗容量和价格寿命余量一定要根据产品预期生命周期反推。1.3 页、块、平面的层级关系以及“擦写不对称”的根源NAND Flash不是以字节为单位寻址的它有一套自己的物理层级页Page读写的最小单位常见大小4KB、8KB、16KB外加一部分备用区Spare Area/OOB备用区用于存放ECC校验值、坏块标记、逻辑映射信息等元数据。块Block擦除的最小单位通常由128、256或512个页组成。平面Plane同一Die内的并行单元多个平面可以同时执行相同操作。DieDie一颗裸片多个Die封装在一起就是常见的NAND Flash芯片。最折磨人的是“读写按页、擦除按块”这种不对称。原因在物理层面擦除需要把整个块衬底抬高电压让所有浮栅里的电子同时隧穿出来而块内所有单元共享衬底没法单独擦除某一页。这种设计让存储介质层就像一块只能整体清除的黑板要修改一个页得先把整块黑板腾出来再重写。这个不对称性直接决定了上层必须引入一层“逻辑地址到物理地址映射”让写入操作可以平移到其他空白页而不是原地覆盖。不理解这一层后面看坏块管理、磨损均衡、垃圾回收都会觉得云里雾里。2. 坏块到底从哪来出厂缺陷与使用磨损是两码事2.1 出厂坏块晶圆制造留下的先天印记很多初学者以为拿到手的NAND Flash是全部完好的实际上任何一颗NAND Flash芯片在出厂时就可能带有坏块这是晶圆制造和封装工艺无法完全避免的。光刻、刻蚀、氧化层生长过程中任何一粒灰尘、一次工艺波动都可能在某个单元上留下缺陷。制造商会把这些块标记出来规则各厂略有差异但大方向一致通常在块0或块1的第一个页有的也在最后一个页的备用区特定位置写入非0xFF的数据表示该块为坏块。这些出厂坏块的数量上限数据手册里一般会给出比如“Max Initial Invalid Block: 2%”意思是出厂坏块比例不超过总量的2%。出厂坏块本身不可怕可怕的是你把它当成好块来用。所以NAND Flash驱动初始化的第一步永远是扫描并建立坏块表这也是后续所有存储逻辑的地基。2.2 使用中长出来的坏块P/E循环与干扰机制使用中产生的坏块叫运行坏块Grown Bad Block或使用坏块Acquired Bad Block它的来源比出厂坏块复杂得多。首先是P/E循环磨损。每次编程和擦除电子都要穿过隧穿氧化层反复高电场冲击会让氧化层产生陷阱电荷和物理损伤。随着P/E次数增加氧化层绝缘能力下降浮栅里的电荷保持能力变弱最终出现编程无法完成、擦除无法完成、数据保持时间骤降等问题。一旦某个单元的失效特征无法通过ECC纠正这个块就会被判为坏块。其次是干扰机制这也是实际项目里最容易被QOS忽略的部分编程干扰Program Disturb编程一个页时同一条字线上其他未选中页的单元也会受到高电压应力阈值电压可能被轻微抬高。读干扰Read Disturb读取一个页时同块其他未读取页的单元也会受到读电压应力误编程的累积效应会让阈值电压缓慢偏移。数据保持损耗Data Retention浮栅里的电荷会随时间缓慢泄漏温度越高泄漏越快。高温烘烤下的数据保持时间可能缩短到常温下的十分之一甚至更少。干扰机制最阴险的地方在于它是“温水煮青蛙”——单元不会瞬间坏掉而是阈值电压一点点漂移直到某次读取时ECC已经救不回来块才正式被判死。2.3 一个经常被误解的问题坏块和ECC是什么关系有人会问既然有ECC纠错坏块直接让ECC纠正不就行了吗这是概念混淆。ECC负责纠正数据读取过程中的比特翻转坏块则是物理层已经不可靠、无法再稳定存储数据的块。ECC可以在一个坏块“萌芽期”充当缓冲区但如果这个块已经无法完成擦除或编程ECC给再多的纠错能力也白搭。理解这个关系对设置ECC纠错阈值很重要。错误比特数一直在安全阈值以内说明块还能用一旦错误比特数持续上涨、接近或超过纠错上限就该主动把这个块降级并搬迁数据了。把ECC当成坏块检测的“早期预警系统”而不是坏块的“救命稻草”这个视角要摆正。3. 出厂坏块识别标记读取、扫描流程与校验细节3.1 出厂坏块标记到底存在哪里NAND Flash的每个Block都有若干个Spare Area出厂坏块标记一般写在Block 0和Block 1的第一个Page的Spare Area特定字节处常用规则是spare area的第1个字节或第0个字节取决于厂商为0xFF表示好块非0xFF表示坏块。不同厂商、不同型号的标记位置可能不同Samsung与Toshiba/铠侠的标记列地址就可能不一样Micron又有自己的一套。拿到新芯片第一件事是去数据手册的“Bad Block Management”章节找标记定义不要凭经验直接写扫描代码。我在项目里见过第三方驱动写死了偏移位置换了一颗不同厂的Flash后把好块当成坏块跳过容量白白少了几个GB。3.2 第一次上电扫描流程为什么不能全信出厂标记出厂标记只能作为初始参考芯片经过封装、运输、焊接、回流焊高温之后可能产生新的坏块。所以量产时的第一次坏块扫描必须在贴片完成后进行一次全片擦除和读写校验而不是直接把出厂标记搬进坏块表。一个实用扫描流程通常是这样的逐块发送擦除命令擦除失败的块直接标记为坏块。对每个块的所有页执行写0xFF或固定Pattern然后读回比对出现数据不一致且无法重写成功的块标记为坏块。再对每块的前几个页执行多次写读循环比对上一次多了不少错误的块也要重点关注。将出厂标记和实际扫描结果合并生成最终坏块表并备份。这里有一个需要注意的细节擦除和写读扫描会消耗P/E次数完整扫描一片大容量Flash是很耗时的。量产效率要求高的话可对整片进行抽样基线检测但可靠性要求高的工业场景强烈建议全量扫描。扫描时用随机Pattern还是固定Pattern我的建议是同时做0x00和0xFF交替写测因为全0写测能暴露出编程不足的问题全1读测能暴露出擦除残留的问题实际误码往往在交替边界处更容易现形。再配合多温度点校验比单温度下测一遍可靠得多。3.3 扫描时的常见误判与处理扫描阶段最容易踩的坑是“假坏块”。有些块只是暂时性编程失败比如操作时序波动、供电电压跌落导致编程电压不够块本身并没有完全损坏。如果不加以区分多试几次编程或者重新擦除后就能恢复正常。成熟的驱动会设置重试机制擦除或编程失败后先重试2~3次多次失败才把块标为坏块。另一个问题是坏块表合并顺序。出厂坏块标记在Block 0/1的Spare Area中如果这两颗块本身就是坏块它们的标记位置可能不可读。处理方式是如果Block 0/1中有一块是坏块仍然要读另一块的标记信息作为出厂坏块Bitmap的补充来源。如果两块全是坏块量产时需要做特殊处理必要时在量产工具里强制指定已知可用块作为系统块替代。4. 运行时坏块管理检测、隔离与FTL层的完整配合4.1 运行时坏块检测的三条路径正式运行阶段坏块检测不能靠定期全盘扫描成本太高。实际靠的是以下三条路径命令失败路径编程或擦除命令返回失败状态位直接标记坏块。读错误路径读取时如果某页校验失败但ECC还能纠回来记录错误地址和错误比特数持续纠错超过阈值后标记坏块。定时巡检路径对长时间未读取的数据块做后台读扫描Background Read Scan把“沉睡”的数据块定期唤醒检查。这项对数据保持类故障尤其有效企业级SSD基本都有后台巡检机制。我建议在固件里把这三条路径都做成事件日志坏块标记操作要留痕。这样后期如果用户报障“数据损坏”你还能回溯出这个块是在哪一天、因为什么事件被标记的。4.2 坏块表怎么维护才不容易丢坏块表Bad Block Table, BBT是闪存管理的核心元数据它要是丢了整片Flash就面临数据找不到的风险。坏块表必须单独预留区域存放通常放在NAND Flash开头几个块中而不是跟用户数据混在一起。我推荐的落盘策略是双副本加序号版本副本存储位置更新方式主BBT系统块区第1份每次变化后写新序号备份BBT系统块区第2份主BBT写成功后同步启动时先读两份BBT比较版本号取最新且CRC校验通过的那份。如果某份读失败直接用另一份重建。如果两份都损坏退回全盘扫描重建。这里要提醒一个常见坑每次坏块表更新都把整张表重写到固定块上会把这个系统落盘块磨损得很快。正确做法是写成“上一版本备份 当前版本”新BBT写在备用块中写完再更新索引。BBT区域本身要走磨损均衡不能只在一个块里反复擦写。4.3 FTL地址映射、磨损均衡与垃圾回收如何协调FTLFlash Translation Layer是三件事的统筹者逻辑地址到物理地址映射、磨损均衡Wear Leveling、垃圾回收Garbage Collection。磨损均衡解决的是“坏块率不均”的问题。同样P/E寿命的块有的被频繁写有的长时间闲着如果只盯着容量用某些块会先老死。动态磨损均衡会在每次写入分配物理页时选择P/E次数最少的块静态磨损均衡会把长期不动的数据搬到老块上把新块腾出来给频繁写入的数据。没有静态均衡少量热数据会集中消耗少数块的寿命整片Flash的实际使用寿命会远低于理论值。垃圾回收则是在后台搬家的过程。因为NAND只能按块擦除一个块里只要还有一页有效数据整块就不能擦。GC会把这些有效页搬到别的空闲块然后整块擦除重新变成可写块。GC中最怕遇到的情况就是搬家搬到一半碰到坏块这时已经在规划中的搬迁数据怎么办正确的做法是先检查新落盘块是否为好块如果块已坏就立即切换备用块继续搬不能中断搬家流程。4.4 ECC与LDPC坏块之外的最后防线再好的坏块管理也不可能让每个块永远不坏ECC是读取路径上的最后一道防线。SLC时代BCH(1,XX)就够用了到了TLC/QLC时代基本都转向LDPC低密度奇偶校验码。LDPC的优势在于它支持软判决可以读取多个参考电压下的比特可靠性信息把“看起来模棱两可”的比特判断得更准。我用一个生活化类比解释BCH像是只看一个字写得像不像LDPC则是把这个字的每一笔都放大看清楚。对于TLC/QLC那种极其微弱的电压差软信息几乎是救命稻草。给E CC留多少冗余、纠错上限调多少直接决定了系统对坏块的容忍度。一般而言LDPC纠错能力配置到codeword的1%~2%是一个常见起点具体要按Flash厂商推荐的BER误码率要求和产品生命周期来算。把纠错上限设置得过激进会导致每个块都要等到病入膏肓才被隔离坏块管理失去提前预警的意义。5. 实际项目里的避坑清单从量产到落地的真实经验5.1 掉电与坏块表的相爱相杀运行时最危险的时刻是掉电瞬间。如果你正在更新BBT写到一半突然掉电坏块表可能永久损坏如果正在垃圾回收搬家数据可能处于新老地址各写一半的状态。没有掉电保护策略的系统每次意外断电都是一次数据完整性赌博。我自己在项目里常用这几招硬件上增加掉电检测电路在电压跌落到危险范围之前触发中断让固件在残存电量里完成当前事务。软件上采用“两阶段提交”先把新BBT写到备用块再把索引指针切换到新块最后再擦掉旧BBT块。数据写入采用“先写新页再更新映射表”的顺序这样即使掉电旧映射表仍然指向旧数据不会产生新老数据都不可用的情况。5.2 OP预留空间不只是为了性能OPOver-Provisioning预留空间通常是用户见不到的那部分容量。很多人把它理解为性能工具——预留多了GC搬运时就有足够的空白块可用写放大可以降低。但OP对坏块管理的意义同样重要。当P/E寿命末期坏块越来越多时如果没有足够的备用好块替换整盘会断崖式进入只读状态。OP空间越大系统对坏块的容忍能力就越强。消费级SSD的OP通常在7%左右企业级会做到15%~28%其中一部分就专门给坏块替换和GC留缓冲。工业级方案如果可靠性优先我建议把OP放到15%以上千万不要为了标称容量好看压缩OP。5.3 ECC/LDPC阈值怎么设定才合理ECC阈值不宜固定不变。最坑人的做法是“有错就纠纠不过来才处理”这样等于放弃了预测性坏块隔离。我惯用的策略是设置两级阈值软阈值错误比特数达到ECC能力上限的50%~70%时就把当前块加入“关注列表”触发数据搬迁并把这个块标记为“即将退役”。硬阈值错误比特数达到上限且搬迁失败直接标记为坏块并更新BBT。这样设定既避免了过早隔离导致容量浪费又能保证在错误进一步恶化前把数据搬走。阈值要按Flash温度环境动态微调高温场景下的BER普遍会更高一些。5.4 量产测试与老化筛选该覆盖哪些项目量产阶段最能筛掉坏块问题。我在产线上推过一套组合拳效果显著上电后先做全片擦除和固定Pattern全片读写校验筛掉贴片损伤和早期失效块。接着做高温烘烤老化比如85℃、若干小时再做一次全片读写校验。这一步能让潜在的Data Retention问题提前现形。最后写入一份带ECC校验的数据到全片断电重启后再读回比对模拟用户“存储后断电过一阵再读”的真实场景。如果成本和工期允许做P/E加速老化测试也很有价值随机写满一轮、校验、再写满两轮、再校验。坏块数量随时间增长的斜率能直观反映这批Flash晶圆的体质。量产测试做得越狠后面运维越省心。特别是那些宣称“工业级”“车规级”的产品如果没有完整坏块数据支撑真出了问题售后成本会远远超过省下来的测试时间。
返回列表