📄 nand_bbt.c
字号:
/*
* drivers/mtd/nand_bbt.c
*
* Overview:
* Bad block table support for the NAND driver
*
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
* $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Description:
*
* When nand_scan_bbt is called, then it tries to find the bad block table
* depending on the options in the bbt descriptor(s). If a bbt is found
* then the contents are read and the memory based bbt is created. If a
* mirrored bbt is selected then the mirror is searched too and the
* versions are compared. If the mirror has a greater version number
* than the mirror bbt is used to build the memory based bbt.
* If the tables are not versioned, then we "or" the bad block information.
* If one of the bbt's is out of date or does not exist it is (re)created.
* If no bbt exists at all then the device is scanned for factory marked
* good / bad blocks and the bad block tables are created.
*
* For manufacturer created bbts like the one found on M-SYS DOC devices
* the bbt is searched and read but never created
*
* The autogenerated bad block table is located in the last good blocks
* of the device. The table is mirrored, so it can be updated eventually.
* The table is marked in the oob area with an ident pattern and a version
* number which indicates which of both tables is more up to date.
*
* The table uses 2 bits per block
* 11b: block is good
* 00b: block is factory marked bad
* 01b, 10b: block is marked bad due to wear
*
* The memory bad block table uses the following scheme:
* 00b: block is good
* 01b: block is marked bad due to wear
* 10b: block is reserved (to protect the bbt area)
* 11b: block is factory marked bad
*
* Multichip devices like DOC store the bad block info per floor.
*
* Following assumptions are made:
* - bbts start at a page boundary, if autolocated on a block boundary
* - the space necessary for a bbt in FLASH does not exceed a block boundary
*
*/
#include "type.h"
#include "flash_lib.h"
#include "string.h"
#include "stdlib.h"
#include "nand_flash.h"
#include "nfc_base.h"
/* The number of bits used per block in the bbt on the device */
#define NAND_BBT_NRBITS_MSK 0x0000000F
#define NAND_BBT_1BIT 0x00000001
#define NAND_BBT_2BIT 0x00000002
#define NAND_BBT_4BIT 0x00000004
#define NAND_BBT_8BIT 0x00000008
/* The bad block table is in the last good block of the device */
#define NAND_BBT_LASTBLOCK 0x00000010
/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_ABSPAGE 0x00000020
/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_SEARCH 0x00000040
/* bbt is stored per chip on multichip devices */
#define NAND_BBT_PERCHIP 0x00000080
/* bbt has a version counter at offset veroffs */
#define NAND_BBT_VERSION 0x00000100
/* Create a bbt if none axists */
#define NAND_BBT_CREATE 0x00000200
/* Search good / bad pattern through all pages of a block */
#define NAND_BBT_SCANALLPAGES 0x00000400
/* Scan block empty during good / bad block scan */
#define NAND_BBT_SCANEMPTY 0x00000800
/* Write bbt if neccecary */
#define NAND_BBT_WRITE 0x00001000
/* Read and write back block contents when writing bbt */
#define NAND_BBT_SAVECONTENT 0x00002000
/* Search good / bad pattern on the first and the second page */
#define NAND_BBT_SCAN2NDPAGE 0x00004000
/* The maximum number of blocks to scan for a bbt */
#define NAND_BBT_SCAN_MAXBLOCKS 4
#define NAND_MAX_CHIPS 8
#define min(a, b) (((a) < (b)) ? (a) : (b))
/**
* 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;
u8 version[NAND_MAX_CHIPS];
int len;
int maxblocks;
int reserved_block_code;
u8 *pattern;
};
/* Generic flash bbt decriptors
*/
static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
static struct nand_bbt_descr bbt_main_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 0,
.len = 4,
.veroffs = 4,
.maxblocks = 4,
.pattern = bbt_pattern
};
static struct nand_bbt_descr bbt_mirror_descr = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 0,
.len = 4,
.veroffs = 4,
.maxblocks = 4,
.pattern = mirror_pattern
};
/**
* check_pattern - [GENERIC] check if a pattern is in the buffer
* @buf: the buffer to search
* @len: the length of buffer to search
* @paglen: the pagelength
* @td: search pattern descriptor
*
* Check for a pattern at the given place. Used to search bad block
* tables and good / bad block identifiers.
* If the SCAN_EMPTY option is set then check, if all bytes except the
* pattern area contain 0xff
*
*/
static int check_pattern(u8 *buf, int len, int paglen, struct nand_bbt_descr *td)
{
int i, end = 0;
u8 *p = buf;
end = paglen + td->offs;
if (td->options & NAND_BBT_SCANEMPTY) {
for (i = 0; i < end; i++) {
if (p[i] != 0xff)
return -1;
}
}
p += end;
/* Compare the pattern */
for (i = 0; i < td->len; i++) {
if (p[i] != td->pattern[i])
return -1;
}
if (td->options & NAND_BBT_SCANEMPTY) {
p += td->len;
end += td->len;
for (i = end; i < len; i++) {
if (*p++ != 0xff)
return -1;
}
}
return 0;
}
/**
* read_bbt - [GENERIC] Read the bad block table starting from page
* @nd: nand device structure
* @buf: temporary buffer
* @page: the starting page
* @num: the number of bbt descriptors to read
* @bits: number of bits per block
* @offs: offset in the memory table
* @reserved_block_code: Pattern to identify reserved blocks
*
* Read the bad block table starting from page.
*
*/
static int read_bbt(nand_t *nd, u8 *buf, int page, int num,
int bits, int offs, int reserved_block_code)
{
int res, i, j, act = 0;
u32 retlen, len, totlen;
u64 from;
u8 msk = (u8) ((1 << bits) - 1);
totlen = (num * bits) >> 3;
from = ((u64) page) * nd->page_size;
while (totlen) {
len = min(totlen, (u32) (nd->page_size * nd->ppb));
res = nand_read((u32)from,(u32)buf,len,NULL);
if (res < 0) {
if (retlen != len) {
return res;
}
}
/* Analyse data */
for (i = 0; i < len; i++) {
u8 dat = buf[i];
for (j = 0; j < 8; j += bits, act += 2) {
u8 tmp = (dat >> j) & msk;
if (tmp == msk)
continue;
if (reserved_block_code && (tmp == reserved_block_code)) {
nd->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
continue;
}
/* Leave it for now, if its matured we can move this
* message to nand_DEBUG_LEVEL0 */
/* Factory marked bad or worn out ? */
if (tmp == 0)
nd->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
else
nd->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
}
}
totlen -= len;
from += len;
}
return 0;
}
/**
* read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
* @nd: nand device structure
* @buf: temporary buffer
* @td: descriptor for the bad block table
* @chip: read the table for a specific chip, -1 read all chips.
* Applies only if NAND_BBT_PERCHIP option is set
*
* Read the bad block table for all chips starting at a given page
* We assume that the bbt bits are in consecutive order.
*/
static int read_abs_bbt(nand_t *nd, u8 *buf, struct nand_bbt_descr *td, int chip)
{
int res = 0, i;
int bits;
bits = td->options & NAND_BBT_NRBITS_MSK;
if (td->options & NAND_BBT_PERCHIP) {
int offs = 0;
for (i = 0; i < 1; i++) {
if (chip == -1 || chip == i)
res = read_bbt (nd, buf, td->pages[i], nd->blk_count, bits, offs, td->reserved_block_code);
if (res)
return res;
offs += (nd->blk_count >> 2);
}
} else {
res = read_bbt (nd, buf, td->pages[0], nd->blk_count, bits, 0, td->reserved_block_code);
if (res)
return res;
}
return 0;
}
/*
* Scan read raw data from flash
*/
static int scan_read_raw(nand_t *nd, u8 *buf, u64 offs,
u32 len)
{
nand_read ((u32)offs, (u32)buf, (u32)len,NULL);
copy_spare(nd,(char *)&buf[len],0,nd->oob_size,1);
return 0;
}
/*
* Scan write data with oob to flash
*/
static int scan_write_bbt(nand_t *nd, u64 offs, u32 len,
u8 *buf, u8 *oob)
{
/* write with user oob */
copy_spare(nd,(char*)&buf[len],0,nd->oob_size,0);
nand_write((u32)offs,(u32)buf,(u32)len,FILE_FORMAT_OPS,NULL);
return 0;
}
/**
* create_bbt - [GENERIC] Create a bad block table by scanning the device
* @nd: nand device structure
* @buf: temporary buffer
* @bd: descriptor 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(nand_t *nd, u8 *buf,struct nand_bbt_descr *bd, int chip)
{
int i, numblocks;
int startblock;
startblock = 0;
numblocks = (nd->blk_count << 1);
for (i = startblock; i < numblocks;) {
int ret;
ret = nand_block_is_good(i >> 1);
if (ret < 0)
return ret;
if (!ret) {
nd->bbt[i >> 3] |= 0x03 << (i & 0x6);
}
i += 2;
}
return 0;
}
/**
* search_bbt - [GENERIC] scan the device for a specific bad block table
* @nd: nand device structure
* @buf: temporary buffer
* @td: descriptor for the bad block table
*
* Read the bad block table by searching for a given ident pattern.
* Search is preformed either from the beginning up or from the end of
* the device downwards. The search starts always at the start of a
* block.
* If the option NAND_BBT_PERCHIP is given, each chip is searched
* for a bbt, which contains the bad block information of this chip.
* This is necessary to provide support for certain DOC devices.
*
* The bbt ident pattern resides in the oob area of the first page
* in a block.
*/
static int search_bbt(nand_t *nd, u8 *buf, struct nand_bbt_descr *td)
{
int i, chips;
int bits, startblock, block, dir;
int scanlen = nd->page_size + nd->oob_size;
int bbtblocks;
/* Search direction top -> down ? */
if (td->options & NAND_BBT_LASTBLOCK) {
startblock = nd->blk_count - 1;
dir = -1;
} else {
startblock = 0;
dir = 1;
}
chips = 1;
bbtblocks = nd->blk_count;
/* Number of bits for each erase block in the bbt */
bits = td->options & NAND_BBT_NRBITS_MSK;
for (i = 0; i < chips; i++) {
/* Reset version information */
td->version[i] = 0;
td->pages[i] = -1;
/* Scan the maximum number of blocks */
for (block = 0; block < td->maxblocks; block++) {
int actblock = startblock + dir * block;
u64 offs = actblock * nd->page_size * nd->ppb ;
/* Read first page */
scan_read_raw(nd, buf, offs, nd->page_size);
if (!check_pattern(buf, scanlen, nd->page_size, td)) {
td->pages[i] = actblock * nd->ppb ;
if (td->options & NAND_BBT_VERSION) {
td->version[i] = buf[nd->page_size + td->veroffs];
}
break;
}
}
startblock += nd->blk_count;
}
return 0;
}
/**
* search_read_bbts - [GENERIC] scan the device for bad block table(s)
* @nd: nand device structure
* @buf: temporary buffer
* @td: descriptor for the bad block table
* @md: descriptor for the bad block table mirror
*
* Search and read the bad block table(s)
*/
static int search_read_bbts(nand_t *nd, u8 * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
/* Search the primary table */
search_bbt(nd, buf, td);
/* Search the mirror table */
if (md)
search_bbt(nd, buf, md);
/* Force result check */
return 1;
}
/**
* write_bbt - [GENERIC] (Re)write the bad block table
*
* @nd: nand device structure
* @buf: temporary buffer
* @td: descriptor for the bad block table
* @md: descriptor for the bad block table mirror
* @chipsel: selector for a specific chip, -1 for all
*
* (Re)write the bad block table
*
*/
static int write_bbt(nand_t *nd, u8 *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -