0.NAND的操作管理方式
???? NAND FLASH的管理方式:以三星FLASH为例,一片Nand flash为一个设备(device),1 (Device) = xxxx (Blocks),1 (Block) = xxxx (Pages),1(Page)?=528 (Bytes) = 数据块大小(512Bytes) + OOB 块大小(16Bytes,除OOB第六字节外,通常至少把OOB的前3个字节存放Nand Flash硬件ECC码)。
????? 关于OOB区,是每个Page都有的。Page大小是512字节的NAND每页分配16字节的OOB;如果NAND物理上是2K的Page,则每个Page分配64字节的OOB。如下图:
???????????? 
以 HYNIX为例,图中黑体的是实际探测到的NAND,是个2G bit(256M)的NAND。PgSize是2K字节,PgsPBlk表示每个BLOCK包含64页,那么每个BLOCK占用的字节数是 64X2K=128K字节;该NAND包好2048个BLOCK,那么可以算出NAND占用的字节数是2048X128K=256M,与实际相符。需要注 意的是SprSize就是OOB大小,也恰好是2K页所用的64字节。
?1.为什么会出现坏块 ?? 由于NAND Flash的工艺不能保证NAND的Memory Array在其生命周期中保持性能的可靠,因此,在NAND的生产中及使用过程中会产生坏块。坏块的特性是:当编程/擦除这个块时,会造成Page Program和Block Erase操作时的错误,相应地反映到Status Register的相应位。
2.坏块的分类 ? 总体上,坏块可以分为两大类:(1)固有坏块:这是生产过程中产生的坏块,一般芯片原厂都会在出厂时都会将每个坏块第一个page的spare area的第6个byte标记为不等于0xff的 值。(2)使用坏块:这是在NAND Flash使用过程中,如果Block Erase或者Page Program错误,就可以简单地将这个块作为坏块来处理,这个时候需要把坏块标记起来。为了和固有坏块信息保持一致,将新发现的坏块的第一个page的 spare area的第6个Byte标记为非0xff的值。
3.坏块管理 ?? 根据上面的这些叙述,可以了解NAND Flash出厂时在spare area中已经反映出了坏块信息,因此, 如果在擦除一个块之前,一定要先check一下第一页的spare area的第6个byte是否是0xff,如果是就证明这是一个好块,可以擦除;如果是非0xff,那么就不能擦除,以免将坏块标记擦掉。 当然,这样处理可能会犯一个错误???“错杀伪坏块”,因为在芯片操作过程中可能由于 电压不稳定等偶然因素会造成NAND操作的错误。但是,为了数据的可靠性及软件设计的简单化,还是需要遵照这个标准。
????? 可以用BBT:bad block table,即坏块表来进行管理。各家对nand的坏块管理方法都有差异。比如专门用nand做存储的,会把bbt放到block0,因为第0块一定是好 的块。但是如果nand本身被用来boot,那么第0块就要存放程序,不能放bbt了。 有的把bbt放到最后一块,当然,这一块坚决不能为坏块。 bbt的大小跟nand大小有关,nand越大,需要的bbt也就越大。
????? 需要注意的是:OOB是每个页都有的数据,里面存的有ECC(当然不仅仅);而BBT是一个FLASH才有一个;针对每个BLOCK的坏块识别则是该块第一页spare area的第六个字节。 4.坏块纠正
????? ECC: NAND Flash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出 错。一般使用一种比较专用的校验――ECC。ECC能纠正单比特错误和检测双比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的 错误不保证能检测。 ????? ECC一般每256字节原始数据生成3字节ECC校验数据,这三字节共24比特分成两部分:6比特的列校验和16比特的行校验,多余的两个比特置1。(512生成两组ECC,共6字节)? ????? 当往NAND Flash的page中写入数据的时候,每256字节我们生成一个ECC校验和,称之为原ECC校验和,保存到PAGE的OOB (out- of-band)数据区中。其位置就是eccpos[]。校验的时候,根据上述ECC生成原理不难推断:将从OOB区中读出的原ECC校验和新ECC校验 和按位异或,若结果为0,则表示不存在错(或是出现了ECC无法检测的错误);若3个字节异或结果中存在11个比特位为1,表示存在一个比特错误,且可纠 正;若3个字节异或结果中只存在1个比特位为1,表示OOB区出错;其他情况均表示出现了无法纠正的错误。 5.补充 (1)需要对前面由于Page Program错误发现的坏块进行一下特别说明。如果在对一个块的某个page进行编程的时候发生了错误就要把这个块标记为坏块,首先就要把块里其他好的 面的内容备份到另外一个空的好块里面,然后,把这个块标记为坏块。当然,这可能会犯“错杀”之误,一个补救的办法,就是在进行完块备份之后,再将这个坏块 擦除一遍,如果Block Erase发生错误,那就证明这个块是个真正的坏块,那就毫不犹豫地将它打个“戳”吧! (2)可能有人会问,为什么要使用每个块第一页的spare area的第六个byte作为坏块标记。这是NAND Flash生产商的默认约定,你可以看到Samsung,Toshiba,STMicroelectronics都是使用这个Byte作为坏块标记的。
???? (3)为什么好块用0xff来标记?因为Nand Flash的擦除即是将相应块的位全部变为1,写操作时只能把芯片每一位(bit)只能从1变为0,而不能从0变为1。0XFF这个值就是标识擦除成功,是好块。
- bbt坏块管理??
- 日月?发表于?-?2010-3-2?9:59:00??
- 2??
- 推荐??
- 前面看到在nand_scan()函数的最后将会跳至scan_bbt()函数,这个函数在nand_scan里面有定义:??
- 2415?if?(!this->scan_bbt)??
- 2416?this->scan_bbt?=?nand_default_bbt;??
- nand_default_bbt()位于Nand_bbt.c文件中。??
- 1047?/**?
- ????*?nand_default_bbt?-?[NAND?Interface]?Select?a?default?bad?block?table?for?the?device?
- ????*?@mtd:?MTD?device?structure?
- ????*?
- ????*?This?selects?the?default?bad?block?table?
- ????*?support?for?the?device?and?calls?the?nand_scan_bbt?
- **/??
- int?nand_default_bbt?(struct?mtd_info?*mtd)??
- {??
- ?struct?nand_chip?*this?=?mtd->priv;??
- 这个函数的作用是建立默认的坏块表。??
- 1059?/*?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?deors?*/??
- ???if?(!this->bbt_td)?{??
- ????this->bbt_td?=?&bbt_main_descr;??
- ????this->bbt_md?=?&bbt_mirror_descr;??
- ???}??
- ????this->options?|=?NAND_USE_FLASH_BBT;??
- ????return?nand_scan_bbt?(mtd,?&agand_flashbased);??
- ???}??
- 如果Flash的类型是AG-AND(这种Flash类型比较特殊,既不是MLC又不是SLC,因此不去深究了,而且好像瑞萨要把它淘汰掉),需要使用默认的模式描述符,最后再进入nand_scan_bbt()函数。??
- 1078?/*?Is?a?flash?based?bad?block?table?requested???*/??
- ???if?(this->options?&?NAND_USE_FLASH_BBT)?{??
- ???/*?Use?the?default?pattern?deors?*/??
- ???if?(!this->bbt_td)?{??
- ????this->bbt_td?=?&bbt_main_descr;??
- ????this->bbt_md?=?&bbt_mirror_descr;??
- ???}??
- ???if?(!this->badblock_pattern)?{??
- ????this->badblock_pattern?=?(mtd->oobblock?>?512)????
- ?????&largepage_flashbased?:?&smallpage_flashbased;??
- ???}??
- ???}?else?{??
- ???this->bbt_td?=?NULL;??
- ???this->bbt_md?=?NULL;??
- ???if?(!this->badblock_pattern)?{??
- ????this->badblock_pattern?=?(mtd->oobblock?>?512)????
- ?????&largepage_memorybased?:?&smallpage_memorybased;??
- ???}??
- ???}??
- ????
- ???return?nand_scan_bbt?(mtd,?this->badblock_pattern);??
- 如果Flash芯片需要使用坏块表,对于1208芯片来说是使用smallpage_memorybased。??
- 985???static?struct?nand_bbt_descr?smallpage_memorybased?=?{??
- ???.options?=?NAND_BBT_SCAN2NDPAGE,??
- ???.offs?=?5,??
- ???.len?=?1,??
- ???.pattern?=?scan_ff_pattern??
- };??
- 暂时没看到如何使用这些赋值,先放着。后面检测坏块时用得着。??
- 1099?return?nand_scan_bbt?(mtd,?this->badblock_pattern);??
- 最后将badblock_pattern作为参数,调用nand_can_bbt函数。??
- 844???/**?
- *?nand_scan_bbt?-?[NAND?Interface]?scan,?find,?read?and?maybe?create?bad?block?table(s)?
- ???*?@mtd:?MTD?device?structure?
- ???*?@bd:???deor?for?the?good/bad?block?search?pattern?
- ???*?
- ???*?The?checks,?if?a?bad?block?table(s)?is/are?already?
- ???*?available.?If?not?it?scans?the?device?for?manufacturer?
- ???*?marked?good?/?bad?blocks?and?writes?the?bad?block?table(s)?to?
- ???*?the?selected?place.?
- ???*?
- ???*?The?bad?block?table?memory?is?allocated?here.?It?must?be?freed?
- ???*?by?calling?the?nand_free_bbt?.?
- ???*?
- */??
- int?nand_scan_bbt?(struct?mtd_info?*mtd,?struct?nand_bbt_descr?*bd)??
- {??
- 检测、寻找、读取甚至建立坏块表。函数检测是否已经存在一张坏块表,否则建立一张。坏块表的内存分配也在这个函数中。??
- 860?struct?nand_chip?*this?=?mtd->priv;??
- int?len,?res?=?0;??
- uint8_t?*buf;??
- struct?nand_bbt_descr?*td?=?this->bbt_td;??
- struct?nand_bbt_descr?*md?=?this->bbt_md;??
- len?=?mtd->size?>>?(this->bbt_erase_shift?+?2);??
- /*?Allocate?memory?(2bit?per?block)?*/??
- this->bbt?=?kmalloc?(len,?GFP_KERNEL);??
- if?(!this->bbt)?{??
- ???printk?(KERN_ERR?"nand_scan_bbt:?Out?of?memory/n");??
- ???return?-ENOMEM;??
- }??
- /*?Clear?the?memory?bad?block?table?*/??
- memset?(this->bbt,?0x00,?len);??
- 一些赋值、变量声明、内存分配,每个block分配2bit的空间。1208有4096个block,应该分配4096*2bit的空间。??
- 877?/*?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)))?{??
- printk?(KERN_ERR?"nand_bbt:?Can't?scan?flash?and?build?the?RAM-based?BBT/n");??
- ????kfree?(this->bbt);??
- ????this->bbt?=?NULL;??
- ???}??
- ???return?res;??
- }??
- 如果没有提供ptd,就扫描设备并建立一张。这里调用了nand_memory_bbt()这个内联函数。??
- 653?/**?
- ???*?nand_memory_bbt?-?[GENERIC]?create?a?memory?based?bad?block?table?
- ???*?@mtd:?MTD?device?structure?
- ???*?@bd:???deor?for?the?good/bad?block?search?pattern?
- ???*?
- ???*?The?creates?a?memory?based?bbt?by?scanning?the?device?
- ???*?for?manufacturer?/?software?marked?good?/?bad?blocks?
- */??
- static?inline?int?nand_memory_bbt?(struct?mtd_info?*mtd,?struct?nand_bbt_descr?*bd)??
- {??
- ???struct?nand_chip?*this?=?mtd->priv;??
- ???bd->options?&=?~NAND_BBT_SCANEMPTY;??
- ???return?create_bbt?(mtd,?this->data_buf,?bd,?-1);??
- }??
- 函数的作用是建立一张基于memory的坏块表。??
- 将操作符的NAND_BBT_SCANEMPTY清除,并继续调用creat_bbt()函数。??
- 271?/**?
- *?create_bbt?-?[GENERIC]?Create?a?bad?block?table?by?scanning?the?device?
- ???*?@mtd:?MTD?device?structure?
- ???*?@buf:?temporary?buffer?
- ???*?@bd:???deor?for?the?good/bad?block?search?pattern?
- ???*?@chip:?create?the?table?for?a?specific?chip,?-1?read?all?chips.?
- ???*???Applies?only?if?NAND_BBT_PERCHIP?option?is?set?
- ???*?
- ???*?Create?a?bad?block?table?by?scanning?the?device?
- ???*?for?the?given?good/bad?block?identify?pattern?
- ???*/??
- static?int?create_bbt?(struct?mtd_info?*mtd,?uint8_t?*buf,?struct?nand_bbt_descr?*bd,?int?chip)??
- {??
- 真正的建立坏块表函数。chip参数是-1表示读取所有的芯片。??
- 284?struct?nand_chip?*this?=?mtd->priv;??
- int?i,?j,?numblocks,?len,?scanlen;??
- int?startblock;??
- loff_t?from;??
- size_t?readlen,?ooblen;??
- printk?(KERN_INFO?"Scanning?device?for?bad?blocks/n");??
- 一些变量声明,开机时那句话就是在这儿打印出来的。??
- 292?if?(bd->options?&?NAND_BBT_SCANALLPAGES)??
- len?=?1?<<?(this->bbt_erase_shift?-?this->page_shift);??
- else?{??
- ???if?(bd->options?&?NAND_BBT_SCAN2NDPAGE)??
- ????len?=?2;??
- ???else??
- ????len?=?1;??
- }??
- 在前面我们定义了smallpage_memorybased这个结构体,现在里面NAND_BBT_SCANALLPAGES的终于用上了,对于1208芯片来说,len=2。??
- 304?if?(!(bd->options?&?NAND_BBT_SCANEMPTY))?{??
- ???/*?We?need?only?read?few?bytes?from?the?OOB?area?*/??
- ???scanlen?=?ooblen?=?0;??
- ???readlen?=?bd->len;??
- }?else?{??
- ???/*?Full?page?content?should?be?read?*/??
- ???scanlen?=?mtd->oobblock?+?mtd->oobsize;??
- ???readlen?=?len?*?mtd->oobblock;??
- ???ooblen?=?len?*?mtd->oobsize;??
- }??
- 前面已经将NAND_BBT_SCANEMPTY清除了,这里肯定执行else的内容。需要将一页内容都读取出来。??
- 316?if?(chip?==?-1)?{??
- ???/*?Note?that?numblocks?is?2?*?(real?numblocks)?here,?see?i+=2?below?as?it?
- ???*?makes?shifting?and?masking?less?painful?*/??
- ???numblocks?=?mtd->size?>>?(this->bbt_erase_shift?-?1);??
- ???startblock?=?0;??
- ???from?=?0;??
- }?else?{??
- ???if?(chip?>=?this->numchips)?{??
- ????printk?(KERN_WARNING?"create_bbt():?chipnr?(%d)?>?available?chips?(%d)/n",??
- ?????chip?+?1,?this->numchips);??
- ????return?-EINVAL;??
- ???}??
- ???numblocks?=?this->chipsize?>>?(this->bbt_erase_shift?-?1);??
- ???startblock?=?chip?*?numblocks;??
- ???numblocks?+=?startblock;??
- ???from?=?startblock?<<?(this->bbt_erase_shift?-?1);??
- }??
- 前面提到chip为-1,实际上我们只有一颗芯片,numblocks这儿是4096*2。??
- 335?for?(i?=?startblock;?i?<?numblocks;)?{??
- ???int?ret;??
- ???if?(bd->options?&?NAND_BBT_SCANEMPTY)??
- ????if?((ret?=?nand_read_raw?(mtd,?buf,?from,?readlen,?ooblen)))??
- ?????return?ret;??
- ???for?(j?=?0;?j?<?len;?j++)?{??
- ????if?(!(bd->options?&?NAND_BBT_SCANEMPTY))?{??
- ?????size_t?retlen;??
- ?????/*?Read?the?full?oob?until?read_oob?is?fixed?to?
- ?????*?handle?single?byte?reads?for?16?bit?buswidth?*/??
- ?????ret?=?mtd->read_oob(mtd,?from?+?j?*?mtd->oobblock,??
- ????????mtd->oobsize,?&retlen,?buf);??
- ?????if?(ret)??
- ??????return?ret;??
- ?????if?(check_short_pattern?(buf,?bd))?{??
- ???????this->bbt[i?>>?3]?|=?0x03?<<?(i?&?0x6);??
- ??????printk?(KERN_WARNING?"Bad?eraseblock?%d?at?0x%08x/n",??
- ???????i?>>?1,?(unsigned?int)?from);??
- ????????break;??
- ?????}??
- ????}?else?{??
- ?????if?(check_pattern?(&buf[j?*?scanlen],?scanlen,?mtd->oobblock,?bd))?{??
- ?????????this->bbt[i?>>?3]?|=?0x03?<<?(i?&?0x6);??
- ??????printk?(KERN_WARNING?"Bad?eraseblock?%d?at?0x%08x/n",?(unsigned?int)?from);??
- ?????????break;??
- ?????}??
- ????}??
- ???}??
- ???i?+=?2;??
- ???from?+=?(1?<<?this->bbt_erase_shift);??
- }??
- return?0;??
- 检测这4096个block,刚开始的nand_read_raw肯定不会执行。len是2,在j循环要循环2次。??
- 每次循环真正要做的事情是下面的内容:??
- ret?=?mtd->read_oob(mtd,?mtd->oobsize,?buf);??
- read_oob()函数在nand_scan()里被指向nand_read_oob(),这个函数在Nand_base.c文件中,看来得回Nand_base.c看看了。??
- 1397?/**?
- ???*?nand_read_oob?-?[MTD?Interface]?NAND?read?out-of-band?
- ???*?@mtd:?MTD?device?structure?
- ???*?@from:?offset?to?read?from?
- ???*?@len:?number?of?bytes?to?read?
- ???*?@retlen:?pointer?to?variable?to?store?the?number?of?read?bytes?
- ???*?@buf:?the?databuffer?to?put?data?
- ???*?
- ???*?NAND?read?out-of-band?data?from?the?spare?area?
- ???*/??
- static?int?nand_read_oob?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*?retlen,?u_char?*?buf)??
- {??
- 才发现oob全称是out-of-band,?from是偏移量,len是读取的长度,retlen是存储指针。??
- 1409?int?i,?col,?page,?chipnr;??
- struct?nand_chip?*this?=?mtd->priv;??
- int?blockcheck?=?(1?<<?(this->phys_erase_shift?-?this->page_shift))?-?1;??
- DEBUG?(MTD_DEBUG_LEVEL3,?"nand_read_oob:?from?=?0x%08x,?len?=?%i/n",?(unsigned?int)?from,?(int)?len);??
- /*?Shift?to?get?page?*/??
- page?=?(int)(from?>>?this->page_shift);??
- chipnr?=?(int)(from?>>?this->chip_shift);??
- /*?Mask?to?get?column?*/??
- col?=?from?&?(mtd->oobsize?-?1);??
- /*?Initialize?return?length?value?*/??
- *retlen?=?0;??
- 一些初始化,blockcheck对于1208应该是(1<<(0xe-0x9)-1)=31。然后通过偏移量计算出要读取oob区的page,chipnr和col。??
- 1425?/*?Do?not?allow?reads?past?end?of?device?*/??
- if?((from?+?len)?>?mtd->size)?{??
- ???DEBUG?(MTD_DEBUG_LEVEL0,?"nand_read_oob:?Attempt?read?beyond?end?of?device/n");??
- ???*retlen?=?0;??
- ???return?-EINVAL;??
- }??
- /*?Grab?the?lock?and?see?if?the?device?is?available?*/??
- nand_get_device?(this,?mtd?,?FL_READING);??
- /*?Select?the?NAND?device?*/??
- this->select_chip(mtd,?chipnr);??
- /*?Send?the?read?command?*/??
- this->cmdfunc?(mtd,?NAND_CMD_READOOB,?page?&?this->pagemask);??
- 不允许非法的读取,获取芯片控制权,发送读取OOB命令,这儿会调用具体硬件驱动中相关的Nand控制函数。??
- 1442?/*?
- *?Read?the?data,?if?we?read?more?than?one?page?
- *?oob?data,?let?the?device?transfer?the?data?!?
- */??
- i?=?0;??
- while?(i?<?len)?{??
- ???int?thislen?=?mtd->oobsize?-?col;??
- ???thislen?=?min_t(int,?thislen,?len);??
- ???this->read_buf(mtd,?&buf[i],?thislen);??
- ???i?+=?thislen;??
- ???/*?Read?more???*/??
- ???if?(i?<?len)?{??
- ????page++;??
- ????col?=?0;??
- ????/*?Check,?if?we?cross?a?chip?boundary?*/??
- ????if?(!(page?&?this->pagemask))?{??
- ?????chipnr++;??
- ?????this->select_chip(mtd,?-1);??
- ?????this->select_chip(mtd,?chipnr);??
- ????}??
- ????/*?Apply?delay?or?wait?for?ready/busy?pin?
- ????*?Do?this?before?the?AUTOINCR?check,?so?no?problems?
- ????*?arise?if?a?chip?which?does?auto?increment?
- ????*?is?marked?as?NOAUTOINCR?by?the?board?driver.?
- ????*/??
- ????if?(!this->dev_ready)??
- ?????udelay?(this->chip_delay);??
- ????else??
- ?????nand_wait_ready(mtd);??
- ????/*?Check,?if?the?chip?supports?auto?page?increment?
- ????*?or?if?we?have?hit?a?block?boundary.?
- ????*/??
- ????if?(!NAND_CANAUTOINCR(this)?||?!(page?&?blockcheck))?{??
- ?????/*?For?subsequent?page?reads?set?offset?to?0?*/??
- ???????????this->cmdfunc?(mtd,?0x0,?page?&?this->pagemask);??
- ????}??
- ???}??
- }??
- /*?Deselect?and?wake?up?anyone?waiting?on?the?device?*/??
- nand_release_device(mtd);??
- /*?Return?happy?*/??
- *retlen?=?len;??
- return?0;??
- 开始读取数据,while循环只要获取到oob区大小的数据即可。注意,read_buf才是最底层的读写Nand的函数,在我们的驱动中根据参数可以实现读取528byte全部内容,或者16byte的oob区。??
- 如果一次没读完,就要继续再读,根据我们实际使用经验好像没出现过这种问题。??
- 最后Return?Happy~回到Nand_bbt.c的creat_bbt()函数,348行,好像都快忘记我们还没出creat_bbt()函数呢,我再把他贴一遍吧:??
- 346???/*?Read?the?full?oob?until?read_oob?is?fixed?to?
- ???*?handle?single?byte?reads?for?16?bit?buswidth?*/??
- ???ret?=?mtd->read_oob(mtd,?(unsigned?int)?from);??
- ?????????break;??
- ?????}??
- ????}??
- ???}??
- ???i?+=?2;??
- ???from?+=?(1?<<?this->bbt_erase_shift);??
- }??
- return?0;??
- }??
- 刚刚如果不是Ruturn?Happy,下面的352行就会返回错误了。接着会调用check_short_pattern()这个函数。??
- 113?/**?
- ???*?check_short_pattern?-?[GENERIC]?check?if?a?pattern?is?in?the?buffer?
- ???*?@buf:?the?buffer?to?search?
- ???*?@td:???search?pattern?deor?
- ???*?
- ???*?Check?for?a?pattern?at?the?given?place.?Used?to?search?bad?block?
- ???*?tables?and?good?/?bad?block?identifiers.?Same?as?check_pattern,?but?
- ???*?no?optional?empty?check?
- ???*?
- */??
- static?int?check_short_pattern?(uint8_t?*buf,?struct?nand_bbt_descr?*td)??
- {??
- int?i;??
- uint8_t?*p?=?buf;??
- /*?Compare?the?pattern?*/??
- for?(i?=?0;?i?<?td->len;?i++)?{??
- ???if?(p[td->offs?+?i]?!=?td->pattern[i])??
- ????return?-1;??
- }??
- return?0;??
- }??
- 检查读到的oob区是不是坏块就靠这个函数了。前面放了好久的struct?nand_bbt_descr?smallpage_memorybased 终于用上了,挨个对比,有一个不一样直接返回-1,坏块就这样产生了。下面会将坏块的位置打印出来,并且将坏块记录在bbt表里面,在 nand_scan_bbt()函数的开始我们就为bbt申请了空间。??
- this->bbt[i?>>?3]?|=?0x03?<<?(i?&?0x6);??
- 为啥要右移3bit呢?首先i要右移1bit,因为前面乘以了2。由于没个block占用2bit的空间,一个char变量8bit,所以还再要右移2bit吧。??
- 下面的check_pattern()函数调用不到的。??
- 依次检测完所有block,creat_bbt()函数也顺利返回。??
- 这样nand_memory_bbt()函数也正确返回。??
- 接着是nand_scan_bbt()同样顺利结束。??
- 最后nand_default_bbt()完成。??
- 整个nand_scan()的工作终于完成咯,好长。?
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|