linuxnand坏块_linux内核中对nand的坏块管理
闲来⽆事,追踪了下linux内核中对nand的坏块管理代码。⼤致记录⼀下。
内核中对nand的坏块管理是在nand的驱动中实现的,⼀般情况下,我们在实现nand控制器的驱动时不⽤考虑坏块的管理,这些机制已经在nand驱动的通⽤框架中实现了,我们要做的就是在nand驱动的框架上对接上nand控制器私有的操作与参数就可以了,例如读写函数以及nand控制器⽀持的ecc布局等。当然,这⾥主要是分析坏块管理的部分,就不多说驱动的开发了。
这⾥的分析是在bcm7231平台的nand驱动上⾯分析的。
nand驱动在加载的时候会调⽤nand_scan_tail函数,此函数的前⾯⼤部分是在确定所使⽤ecc⽅式和函数指针,以及⼀个页的读写需要作⼏次ecc校验等,这些都是根据nand驱动初始化的时候指定的⼀些参数决定的。在此函数的最后⾯开始关于BBT的操作:
/* Check, if we should skip the bad block table scan */
if(chip->options & NAND_SKIP_BBTSCAN)
return0;
/* Build bad block table */
returnchip->scan_bbt(mtd);⾸先会检查chip->options中是否有NAND_SKIP_BBTSCAN选项,如果有,则直接返
回,NAND_SKIP_BBTSCAN⼀般是在nand控制器驱动中选择是否被赋予的,⼀般不会赋予NAND_SKIP_BBTSCAN选项。如果没有,则调⽤chip->scan_bbt()函数。chip->scan_bbt()是⼀个函数指针,⼀般在nand_set_defaults中被赋值为nand_default_bbt。
⾸先我们看下struct nand_chip结构体中关于BBT的部分:
/**
*... ...
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup.
* @bbt_md: [REPLACEABLE] bad block table mirror descriptor
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
* bad block scan.
*... ...
*/
structnand_chip {
……
uint8_t *bbt
structnand_bbt_descr *bbt_td;
structnand_bbt_descr *bbt_md;
structnand_bbt_descr *badblock_pattern;
…
…
};
bbt是在内存中分配的⼀块内存(nand_scan_bbt中分配的,后⾯会说到),这块内存会存放BBT。如果定义了NAND_BBT_USE_FLASH(这个可以在编写nand控制器驱动时选择),会先在nand中查BBT是否存在,如果存在,然后读出放在bbt中,如果不存在(全新flash会有这种情况),则在bbt中建⽴BBT,然后写⼊nand中。如果没有定义NAND_BBT_USE_FLASH,那么会直接在bbt指向的内存中建⽴BBT。
bbt_td、bbt_md和badblock_pattern就是在nand_default_bbt函数中赋值的3个结构体。它们虽然是相同的结构体类型,但却有不同的作⽤和含义。其中bbt_td和bbt_md是主bbt和镜像bbt的描述符(镜像bbt主要⽤来对bbt的update和备份),它们只在把bbt存储在NAND芯⽚的情况下使⽤,⽤来从NAND芯⽚中查bbt。若bbt存储在内存中,bbt_td和bbt_md将会被赋值为NULL。
badblock_pattern就是坏块信息的pattern,其中定义了坏块信息在oob中的存储位置,以及内容(即⽤什么值表⽰这个block是个坏块)。通常⽤1或2个字节来标志⼀个block是否为坏块,这1或2个字节就是坏块信息,如果这1或2个字节的内容是0xff,那就说明这个block是好的,否则就是坏块。对于坏块信息在NAND芯⽚中的存储位置,small page(每页512 Byte)和big page(每页2048 Byte)的两种NAND 芯
⽚不尽相同。⼀般来说,small page的NAND芯⽚,坏块信息存储在每个block的第⼀个page的oob的第六个字节中,⽽big page的NAND芯⽚,坏块信息存储在每个block的第⼀个page的oob的第1和第2个字节中。即使某种NAND芯⽚的坏块信息不是这样的存储⽅式也没关系,因为我们可以在badblock_pattern中⾃⼰指定坏块信息的存储位置,以及⽤什么值来标志坏块(其实这个值表⽰的应该是“好块”,因为MTD会把从oob中坏块信息存储位置读出的内容与这个值做⽐较,若相等,则表⽰是个“好块”,否则就是坏块)。
下⾯是nand_default_bbt的实现:
/**
* nand_default_bbt - [NAND Interface] Select a default bad block table for the device
* @mtd: MTD device structure
*
* This function selects the default bad block table support for the device and
* calls the nand_scan_bbt function.
*/
intnand_default_bbt(structmtd_info *mtd)
{
structnand_chip *this= mtd->priv;
/*
* Default for AG-AND. We must use a flash based bad block table as the
* devices have factory marked _good_ blocks. Erasing those blocks
* leads to loss of the good / bad information, so we _must_ store this
* information in a good / bad table during startup.
*/
if(this->options & NAND_IS_AND) {
/
* Use the default pattern descriptors */
if(!this->bbt_td) {
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
}
this->bbt_options |= NAND_BBT_USE_FLASH;
returnnand_scan_bbt(mtd, &agand_flashbased);
}
/* Is a flash based bad block table requested? */
if(this->bbt_options & NAND_BBT_USE_FLASH) {
/* Use the default pattern descriptors */
if(!this->bbt_td) {
if(this->bbt_options & NAND_BBT_NO_OOB) {
this->bbt_td = &bbt_main_no_bbt_descr;
this->bbt_md = &bbt_mirror_no_bbt_descr;
}else{
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
}
}
}else{
this->bbt_td = NULL;
this->bbt_md = NULL;
}
if(!this->badblock_pattern)
nand_create_badblock_pattern(this);
returnnand_scan_bbt(mtd,this->badblock_pattern);
}
在分析nand_scan_bbt函数之前先介绍下struct nand_bbt_descr的各成员的含义。其定义如下:/**
* struct nand_bbt_descr - bad block table descriptor
* @options: options for this descriptor
* @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
* when bbt is searched, then we store the found bbts pages here.
* Its an array and supports up to 8 chips now
* @offs: offset of the pattern in the oob area of the page
* @veroffs: offset of the bbt version counter in the oob are of the page
* @version: version read from the bbt page during scan
* @len: length of the pattern, if 0 no pattern check is performed
* @maxblocks: maximum number of blocks to search for a bbt. This number of
* blocks is reserved at the end of the device where the tables are
* written.
* @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
* bad) block in the stored bbt
* @pattern: pattern to identify bad block table or factory marked good /
* bad blocks, can be NULL, if len = 0
*
* Descriptor for the bad block table marker and the descriptor for the
* pattern which identifies good and bad blocks. The assumption is made
* that the pattern and the version count are always located in the oob area
* of the first block.
*/
struct nand_bbt_descr {
int options;
int pages[NAND_MAX_CHIPS];
int offs;
int veroffs;
uint8_t version[NAND_MAX_CHIPS];
int len;
int maxblocks;
replaceableint reserved_block_code;
uint8_t *pattern;
};
options:bad block table或者bad block的选项,可⽤的选择以及各选项具体表⽰什么含义,可以参考。
pages:bbt专⽤。在查bbt的时候,若到了bbt,就把bbt所在的page号保存在这个成员变量中。若没到bbt,就会把新建⽴的bbt的保存位置赋值给它。因为系统中可能会有多个NAND芯⽚,我们可以为每⼀⽚NAND芯⽚建⽴⼀个bbt,也可以只在其中⼀⽚NAND芯⽚中建⽴唯⼀的⼀个bbt,所以这⾥的
pages是个维数为NAND_MAX_CHIPS的数值,⽤来保存每⼀⽚NAND芯⽚的bbt位置。当然,若只建⽴了⼀个bbt,那么就只使⽤pages[0]。
offs、len和pattern:MTD会从oob的offs中读出len长度的内容,然后与pattern指针指向的内容做⽐较,若相等,则表⽰到了bbt,或者表⽰这个block是好的。
veroffs和version:bbt专⽤。MTD会从oob的veroffs中读出⼀个字节的内容,作为bbt的版本值保存在version中。
maxblocks:bbt专⽤。MTD在查bbt的时候,不会查NAND芯⽚中所有的block,⽽是最多查maxblocks个block。
下⾯接着分析nand_scan_bbt函数。
bcm7231的nand控制器驱动中有这么⼀⾏:chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;所以,上⾯函数的⾛向也很明确。
在最后调⽤了nand_scan_bbt函数。此函数的注释有这么⼀句话:
/**
* nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) ... ...
*/可见,BBT的相关⼯作基本都是在这个函数内完成的。其函数实现如下:
intnand_scan_bbt(structmtd_info *mtd,structnand_bbt_descr *bd)
{
structnand_chip *this= mtd->priv;
intlen, res = 0;
uint8_t *buf;
structnand_bbt_descr *td =this->bbt_td;
structnand_bbt_descr *md =this->bbt_md;
len = mtd->size >> (this->bbt_erase_shift + 2);
/*
* Allocate memory (2bit per block) and clear the memory bad block
* table.
*/
this->bbt = kzalloc(len, GFP_KERNEL);
if(!this->bbt) {
printk(KERN_ERR"nand_scan_bbt: Out of memory\n");
return-ENOMEM;
}
/*
* If no primary table decriptor is given, scan the device to build a
* memory based bad block table.
*/
if(!td) {
if((res = nand_memory_bbt(mtd, bd))) {
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
kfree(this->bbt);
this->bbt = NULL;
}
returnres;
}
verify_bbt_descr(mtd, td);
verify_bbt_descr(mtd, md);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论