11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  drivers/mtd/nand_bbt.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Overview:
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Bad block table support for the NAND driver
661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description:
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * When nand_scan_bbt is called, then it tries to find the bad block table
167cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * depending on the options in the BBT descriptor(s). If no flash based BBT
17bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
187cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * marked good / bad blocks. This information is used to create a memory BBT.
197cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * Once a new bad block is discovered then the "factory" information is updated
207cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * on the device.
217cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * If a flash based BBT is specified then the function first tries to find the
227cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * BBT on flash. If a BBT is found then the contents are read and the memory
237cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * based BBT is created. If a mirrored BBT is selected then the mirror is
247cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * searched too and the versions are compared. If the mirror has a greater
257cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * version number than the mirror BBT is used to build the memory based BBT.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the tables are not versioned, then we "or" the bad block information.
277cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * If one of the BBTs is out of date or does not exist it is (re)created.
287cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * If no BBT exists at all then the device is scanned for factory marked
2961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * good / bad blocks and the bad block tables are created.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
317cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * For manufacturer created BBTs like the one found on M-SYS DOC devices
327cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * the BBT is searched and read but never created
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
347cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * The auto generated bad block table is located in the last good blocks
3561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * of the device. The table is mirrored, so it can be updated eventually.
367cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * The table is marked in the OOB area with an ident pattern and a version
377cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * number which indicates which of both tables is more up to date. If the NAND
387cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * controller needs the complete OOB area for the ECC information then the
39bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
40a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris * course): it moves the ident pattern and the version byte into the data area
41a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris * and the OOB area will remain untouched.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The table uses 2 bits per block
447cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * 11b:		block is good
457cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * 00b:		block is factory marked bad
467cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * 01b, 10b:	block is marked bad due to wear
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The memory bad block table uses the following scheme:
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 00b:		block is good
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 01b:		block is marked bad due to wear
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10b:		block is reserved (to protect the bbt area)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11b:		block is factory marked bad
5361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner *
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Multichip devices like DOC store the bad block info per floor.
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Following assumptions are made:
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - bbts start at a page boundary, if autolocated on a block boundary
58e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse * - the space necessary for a bbt in FLASH does not exceed a block boundary
5961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner *
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/nand.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/nand_ecc.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
69c3f8abf481c2d2b221b028f7369bc6dd39a9590eDavid Woodhouse#include <linux/vmalloc.h>
70f3bcc0179ab8145615a3b409d652cad1395fb7f3Paul Gortmaker#include <linux/export.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
727cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
737cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
747cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	int ret;
757cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
767cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	ret = memcmp(buf, td->pattern, td->len);
777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!ret)
787cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return ret;
797cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	return -1;
807cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
817cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
8261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner/**
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check_pattern - [GENERIC] check if a pattern is in the buffer
848b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: the buffer to search
858b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @len: the length of buffer to search
868b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @paglen: the pagelength
878b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: search pattern descriptor
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
898b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Check for a pattern at the given place. Used to search bad block tables and
908b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
918b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * all bytes except the pattern area contain 0xff.
928b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
93e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
95171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy	int i, end = 0;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *p = buf;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
987cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_NO_OOB)
997cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return check_pattern_no_oob(buf, td);
1007cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
101c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	end = paglen + td->offs;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_SCANEMPTY) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < end; i++) {
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (p[i] != 0xff)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -1;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
108c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	p += end;
10961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Compare the pattern */
11175b66d8ccd5772b00a7328c2cf75bc506ec532a1Brian Norris	if (memcmp(p, td->pattern, td->len))
11275b66d8ccd5772b00a7328c2cf75bc506ec532a1Brian Norris		return -1;
11358373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_SCANEMPTY) {
115171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		p += td->len;
116171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		end += td->len;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = end; i < len; i++) {
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (*p++ != 0xff)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -1;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner/**
126c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner * check_short_pattern - [GENERIC] check if a pattern is in the buffer
1278b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: the buffer to search
1288b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td:	search pattern descriptor
129c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner *
1308b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Check for a pattern at the given place. Used to search bad block tables and
1318b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * good / bad block identifiers. Same as check_pattern, but no optional empty
1328b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * check.
1338b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
134e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
135c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner{
136c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	int i;
137c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	uint8_t *p = buf;
138c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner
139c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	/* Compare the pattern */
140c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	for (i = 0; i < td->len; i++) {
14119870da7ea2fc483bf73a189046a430fd9b01391Thomas Gleixner		if (p[td->offs + i] != td->pattern[i])
142c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner			return -1;
143c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	}
144c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	return 0;
145c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner}
146c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1487cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * add_marker_len - compute the length of the marker in data area
1498b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: BBT descriptor used for computation
1507cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior *
1517854d3f7495b11be1570cd3e2318674d8f9ed797Brian Norris * The length will be 0 if the marker is located in OOB area.
1527cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior */
1537cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic u32 add_marker_len(struct nand_bbt_descr *td)
1547cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
1557cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 len;
1567cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
1577cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!(td->options & NAND_BBT_NO_OOB))
1587cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return 0;
1597cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
1607cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	len = td->len;
1617cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_VERSION)
1627cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		len++;
1637cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	return len;
1647cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
1657cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
1667cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior/**
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read_bbt - [GENERIC] Read the bad block table starting from page
1688b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
1698b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
1708b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @page: the starting page
1718b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @num: the number of bbt descriptors to read
1727854d3f7495b11be1570cd3e2318674d8f9ed797Brian Norris * @td: the bbt describtion table
1738b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @offs: offset in the memory table
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the bad block table starting from page.
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
177e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
178df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior		struct nand_bbt_descr *td, int offs)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
180167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris	int res, ret = 0, i, j, act = 0;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t retlen, len, totlen;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loff_t from;
184df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior	int bits = td->options & NAND_BBT_NRBITS_MSK;
185596d74527a804418d88e1178c9d72aff5649e89cBrian Norris	uint8_t msk = (uint8_t)((1 << bits) - 1);
1867cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 marker_len;
187df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior	int reserved_block_code = td->reserved_block_code;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	totlen = (num * bits) >> 3;
1907cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	marker_len = add_marker_len(td);
191596d74527a804418d88e1178c9d72aff5649e89cBrian Norris	from = ((loff_t)page) << this->page_shift;
19261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (totlen) {
194596d74527a804418d88e1178c9d72aff5649e89cBrian Norris		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
1957cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		if (marker_len) {
1967cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/*
1977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 * In case the BBT marker is not in the OOB area it
1987cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 * will be just in the first page.
1997cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 */
2007cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			len -= marker_len;
2017cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			from += marker_len;
2027cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			marker_len = 0;
2037cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		}
204329ad399a9b3adf52c90637b21ca029fcf7f8795Artem Bityutskiy		res = mtd_read(mtd, from, len, &retlen, buf);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res < 0) {
206167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris			if (mtd_is_eccerr(res)) {
207167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris				pr_info("nand_bbt: ECC error in BBT at "
208167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris					"0x%012llx\n", from & ~mtd->writesize);
209167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris				return res;
210167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris			} else if (mtd_is_bitflip(res)) {
211167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris				pr_info("nand_bbt: corrected error in BBT at "
212167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris					"0x%012llx\n", from & ~mtd->writesize);
213167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris				ret = res;
214167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris			} else {
215167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris				pr_info("nand_bbt: error reading BBT\n");
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
21861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Analyse data */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < len; i++) {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uint8_t dat = buf[i];
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (j = 0; j < 8; j += bits, act += 2) {
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				uint8_t tmp = (dat >> j) & msk;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tmp == msk)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
227e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse				if (reserved_block_code && (tmp == reserved_block_code)) {
228d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
229d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris						 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
231f1a28c02843efcfcc41982149880bac3ac180234Thomas Gleixner					mtd->ecc_stats.bbtblocks++;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2348b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				/*
2358b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				 * Leave it for now, if it's matured we can
236a0f5080ecc1c75f9c08591d9b0f48451e7ac8ddcBrian Norris				 * move this message to pr_debug.
2378b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				 */
238d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
239d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
2408b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				/* Factory marked bad or worn out? */
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tmp == 0)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
245f1a28c02843efcfcc41982149880bac3ac180234Thomas Gleixner				mtd->ecc_stats.badblocks++;
24661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner			}
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		totlen -= len;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from += len;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
251167a8d52509a0f7d6728a79e2588b800e866c147Brian Norris	return ret;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
2568b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
2578b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
2588b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
259596d74527a804418d88e1178c9d72aff5649e89cBrian Norris * @chip: read the table for a specific chip, -1 read all chips; applies only if
2608b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris *        NAND_BBT_PERCHIP option is set
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2628b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Read the bad block table for all chips starting at a given page. We assume
2638b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * that the bbt bits are in consecutive order.
2648b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
265e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res = 0, i;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int offs = 0;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < this->numchips; i++) {
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip == -1 || chip == i)
274df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior				res = read_bbt(mtd, buf, td->pages[i],
275df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior					this->chipsize >> this->bbt_erase_shift,
276df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior					td, offs);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs += this->chipsize >> (this->bbt_erase_shift + 2);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
282df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior		res = read_bbt(mtd, buf, td->pages[0],
283df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior				mtd->size >> this->bbt_erase_shift, td, 0);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res)
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return res;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2908b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* BBT marker is in the first page, no OOB */
2917cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
2927cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 struct nand_bbt_descr *td)
2937cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
2947cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	size_t retlen;
2957cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	size_t len;
2967cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
2977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	len = td->len;
2987cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_VERSION)
2997cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		len++;
3007cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
301329ad399a9b3adf52c90637b21ca029fcf7f8795Artem Bityutskiy	return mtd_read(mtd, offs, len, &retlen, buf);
3027cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
3037cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
3048b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan read raw data from flash */
3057cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
3068593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			 size_t len)
3078593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
3088593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
309b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	int res;
3108593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3110612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_RAW;
3128593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
3138593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
3148593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
315b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	while (len > 0) {
316105513cc4a25522f959788371bd612f987d4d184Brian Norris		ops.datbuf = buf;
317105513cc4a25522f959788371bd612f987d4d184Brian Norris		ops.len = min(len, (size_t)mtd->writesize);
318105513cc4a25522f959788371bd612f987d4d184Brian Norris		ops.oobbuf = buf + ops.len;
319b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky
320fd2819bbc92fc98bed5d612e4acbe16b6326f6bfArtem Bityutskiy		res = mtd_read_oob(mtd, offs, &ops);
321b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky
322afa17de262633603dd65f89e9370f48e56b8c557Brian Norris		if (res)
323105513cc4a25522f959788371bd612f987d4d184Brian Norris			return res;
324b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky
325b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky		buf += mtd->oobsize + mtd->writesize;
326b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky		len -= mtd->writesize;
327a5b57cd820528f863d519ac5a0f6a94e5e8b3a0eDmitry Maluka		offs += mtd->writesize;
328b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	}
329b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	return 0;
3308593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
3318593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3327cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
3337cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 size_t len, struct nand_bbt_descr *td)
3347cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
3357cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_NO_OOB)
3367cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return scan_read_raw_data(mtd, buf, offs, td);
3377cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	else
3387cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return scan_read_raw_oob(mtd, buf, offs, len);
3397cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
3407cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
3418b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan write data with oob to flash */
3428593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
3438593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			  uint8_t *buf, uint8_t *oob)
3448593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
3458593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
3468593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3470612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_PLACE_OOB;
3488593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
3498593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
3508593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.datbuf = buf;
3518593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.oobbuf = oob;
3528593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.len = len;
3538593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
354a2cc5ba075f9bc837d0b4d4ec7328dcefc11859dArtem Bityutskiy	return mtd_write_oob(mtd, offs, &ops);
3558593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
3568593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3577cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
3587cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
3597cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 ver_offs = td->veroffs;
3607cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
3617cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!(td->options & NAND_BBT_NO_OOB))
3627cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		ver_offs += mtd->writesize;
3637cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	return ver_offs;
3647cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
3657cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
3688b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
3698b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
3708b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
3718b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @md:	descriptor for the bad block table mirror
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3738b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Read the bad block table(s) for all chips starting at a given page. We
3748b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * assume that the bbt bits are in consecutive order.
3758b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
3768593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
3778593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			 struct nand_bbt_descr *td, struct nand_bbt_descr *md)
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	/* Read the primary version, if available */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_VERSION) {
38369423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
3847cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			      mtd->writesize, td);
3857cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
3869a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris		pr_info("Bad block table at page %d, version 0x%02X\n",
387d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			 td->pages[0], td->version[0]);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	/* Read the mirror version, if available */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md && (md->options & NAND_BBT_VERSION)) {
39269423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
3937cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			      mtd->writesize, td);
3947cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
3959a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris		pr_info("Bad block table at page %d, version 0x%02X\n",
396d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			 md->pages[0], md->version[0]);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4018b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan a given block full */
4028593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
4038593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			   loff_t offs, uint8_t *buf, size_t readlen,
4048593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			   int scanlen, int len)
4058593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
4068593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int ret, j;
4078593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4087cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	ret = scan_read_raw_oob(mtd, buf, offs, readlen);
409afa17de262633603dd65f89e9370f48e56b8c557Brian Norris	/* Ignore ECC errors when checking for BBM */
410d57f40544a41fdfe90fd863b6865138c5a82f1ccBrian Norris	if (ret && !mtd_is_bitflip_or_eccerr(ret))
4118593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		return ret;
4128593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4138593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	for (j = 0; j < len; j++, buf += scanlen) {
4148593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (check_pattern(buf, scanlen, mtd->writesize, bd))
4158593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return 1;
4168593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	}
4178593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	return 0;
4188593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
4198593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4208b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan a given block partially */
4218593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
4228593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			   loff_t offs, uint8_t *buf, int len)
4238593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
4248593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
4258593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int j, ret;
4268593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4278593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
4288593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.oobbuf = buf;
4298593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
4308593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.datbuf = NULL;
4310612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_PLACE_OOB;
4328593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4338593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	for (j = 0; j < len; j++) {
4348593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		/*
4358b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * Read the full oob until read_oob is fixed to handle single
4368b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * byte reads for 16 bit buswidth.
4378593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		 */
438fd2819bbc92fc98bed5d612e4acbe16b6326f6bfArtem Bityutskiy		ret = mtd_read_oob(mtd, offs, &ops);
439903cd06cd6ece7f9050a3ad5b03e0b76be2882ffBrian Norris		/* Ignore ECC errors when checking for BBM */
440d57f40544a41fdfe90fd863b6865138c5a82f1ccBrian Norris		if (ret && !mtd_is_bitflip_or_eccerr(ret))
4418593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return ret;
4428593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4438593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (check_short_pattern(buf, bd))
4448593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return 1;
4458593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4468593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		offs += mtd->writesize;
4478593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	}
4488593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	return 0;
4498593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
4508593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * create_bbt - [GENERIC] Create a bad block table by scanning the device
4538b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
4548b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
4558b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
4568b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @chip: create the table for a specific chip, -1 read all chips; applies only
4578b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris *        if NAND_BBT_PERCHIP option is set
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4598b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Create a bad block table by scanning the device for the given good/bad block
4608b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * identify pattern.
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4628593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int create_bbt(struct mtd_info *mtd, uint8_t *buf,
4638593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct nand_bbt_descr *bd, int chip)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
4668593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int i, numblocks, len, scanlen;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int startblock;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loff_t from;
4698593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	size_t readlen;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4719a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris	pr_info("Scanning device for bad blocks\n");
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bd->options & NAND_BBT_SCANALLPAGES)
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = 1 << (this->bbt_erase_shift - this->page_shift);
47558373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	else if (bd->options & NAND_BBT_SCAN2NDPAGE)
47658373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		len = 2;
47758373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	else
47858373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		len = 1;
479171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy
480171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy	if (!(bd->options & NAND_BBT_SCANEMPTY)) {
481171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		/* We need only read few bytes from the OOB area */
4828593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		scanlen = 0;
483eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		readlen = bd->len;
484eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	} else {
485171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		/* Full page content should be read */
48628318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel		scanlen = mtd->writesize + mtd->oobsize;
48728318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel		readlen = len * mtd->writesize;
488eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip == -1) {
4918b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
4928b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * Note that numblocks is 2 * (real numblocks) here, see i+=2
4938b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * below as it makes shifting and masking less painful
4948b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		numblocks = mtd->size >> (this->bbt_erase_shift - 1);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock = 0;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from = 0;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chip >= this->numchips) {
5009a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
501e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			       chip + 1, this->numchips);
502171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy			return -EINVAL;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock = chip * numblocks;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		numblocks += startblock;
50769423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		from = (loff_t)startblock << (this->bbt_erase_shift - 1);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
50961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5105fb1549dfc40f3b589dae560ea21535cdc5f64e0Brian Norris	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
511b60b08b02ca8d9575985ae6711bd656dd67e9039Kevin Cernekee		from += mtd->erasesize - (mtd->writesize * len);
512b60b08b02ca8d9575985ae6711bd656dd67e9039Kevin Cernekee
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = startblock; i < numblocks;) {
514eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		int ret;
51561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5167cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		BUG_ON(bd->options & NAND_BBT_NO_OOB);
5177cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
5188593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (bd->options & NAND_BBT_SCANALLPAGES)
5198593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			ret = scan_block_full(mtd, bd, from, buf, readlen,
5208593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner					      scanlen, len);
5218593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		else
5228593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			ret = scan_block_fast(mtd, bd, from, buf, len);
5238593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5248593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (ret < 0)
5258593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return ret;
5268593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5278593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (ret) {
5288593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			this->bbt[i >> 3] |= 0x03 << (i & 0x6);
5299a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris			pr_warn("Bad eraseblock %d at 0x%012llx\n",
530d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				i >> 1, (unsigned long long)from);
531f1a28c02843efcfcc41982149880bac3ac180234Thomas Gleixner			mtd->ecc_stats.badblocks++;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5338593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i += 2;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from += (1 << this->bbt_erase_shift);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
537eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	return 0;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search_bbt - [GENERIC] scan the device for a specific bad block table
5428b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
5438b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
5448b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5468b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Read the bad block table by searching for a given ident pattern. Search is
5478b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * preformed either from the beginning up or from the end of the device
5488b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * downwards. The search starts always at the start of a block. If the option
5498b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
5508b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the bad block information of this chip. This is necessary to provide support
5518b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * for certain DOC devices.
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5538b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The bbt ident pattern resides in the oob area of the first page in a block.
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
555e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, chips;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bits, startblock, block, dir;
56028318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel	int scanlen = mtd->writesize + mtd->oobsize;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bbtblocks;
5628593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int blocktopage = this->bbt_erase_shift - this->page_shift;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5648b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Search direction top -> down? */
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_LASTBLOCK) {
566e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		startblock = (mtd->size >> this->bbt_erase_shift) - 1;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dir = -1;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
56961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		startblock = 0;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dir = 1;
57161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
57261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5738b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = this->numchips;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bbtblocks = this->chipsize >> this->bbt_erase_shift;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock &= bbtblocks - 1;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = 1;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bbtblocks = mtd->size >> this->bbt_erase_shift;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
58261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Number of bits for each erase block in the bbt */
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bits = td->options & NAND_BBT_NRBITS_MSK;
58561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset version information */
58861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		td->version[i] = 0;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td->pages[i] = -1;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Scan the maximum number of blocks */
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (block = 0; block < td->maxblocks; block++) {
5928593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int actblock = startblock + dir * block;
59469423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
5958593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Read first page */
5977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			scan_read_raw(mtd, buf, offs, mtd->writesize, td);
59828318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
5998593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner				td->pages[i] = actblock << blocktopage;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (td->options & NAND_BBT_VERSION) {
6017cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior					offs = bbt_get_ver_offs(mtd, td);
6027cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior					td->version[i] = buf[offs];
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock += this->chipsize >> this->bbt_erase_shift;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check, if we found a bbt for each requested chip */
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->pages[i] == -1)
6129a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris			pr_warn("Bad block table not found for chip %d\n", i);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
614d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			pr_info("Bad block table found at page %d, version "
615d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				 "0x%02X\n", td->pages[i], td->version[i]);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
61761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	return 0;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search_read_bbts - [GENERIC] scan the device for bad block table(s)
6228b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
6238b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
6248b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
6258b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @md: descriptor for the bad block table mirror
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6278b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Search and read the bad block table(s).
6288b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
629e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Search the primary table */
632e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	search_bbt(mtd, buf, td);
63361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Search the mirror table */
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md)
636e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		search_bbt(mtd, buf, md);
63761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Force result check */
63961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	return 1;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner/**
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write_bbt - [GENERIC] (Re)write the bad block table
6448b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
6458b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
6468b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
6478b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @md: descriptor for the bad block table mirror
6488b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @chipsel: selector for a specific chip, -1 for all
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6508b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * (Re)write the bad block table.
6518b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
652e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int write_bbt(struct mtd_info *mtd, uint8_t *buf,
6539223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
6549223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		     int chipsel)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct erase_info einfo;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, res, chip = 0;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
6609223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner	int nrchips, bbtoffs, pageoffs, ooboffs;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t msk[4];
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t rcode = td->reserved_block_code;
6638593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	size_t retlen, len = 0;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loff_t to;
6658593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
6668593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
6678593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
6688593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
6698593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.datbuf = NULL;
6700612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_PLACE_OOB;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rcode)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rcode = 0xff;
6748b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Write bad block table per chip rather than per device? */
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
676e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
6778b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Full device write or specific chip? */
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chipsel == -1) {
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nrchips = this->numchips;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nrchips = chipsel + 1;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			chip = chipsel;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
685e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrchips = 1;
68761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
68861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Loop through the chips */
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; chip < nrchips; chip++) {
6918b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
6928b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * There was already a version of the table, reuse the page
69361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		 * This applies for absolute placement too, as we have the
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * page nr. in td->pages.
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->pages[chip] != -1) {
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			page = td->pages[chip];
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto write;
69961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7018b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
7028b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * Automatic placement of the bad block table. Search direction
7038b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * top -> down?
7048b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 */
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->options & NAND_BBT_LASTBLOCK) {
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			startblock = numblocks * (chip + 1) - 1;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dir = -1;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			startblock = chip * numblocks;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dir = 1;
71161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < td->maxblocks; i++) {
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int block = startblock + dir * i;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check, if the block is bad */
7169223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			switch ((this->bbt[block >> 2] >>
7179223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				 (2 * (block & 0x03))) & 0x03) {
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 0x01:
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 0x03:
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7229223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			page = block <<
7239223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				(this->bbt_erase_shift - this->page_shift);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check, if the block is used by the mirror table */
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!md || md->pages[chip] != page)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto write;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7289a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris		pr_err("No space left to write bad block table\n");
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOSPC;
730e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	write:
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Set up shift count and masks for the flash table */
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bits = td->options & NAND_BBT_NRBITS_MSK;
7349223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		msk[2] = ~rcode;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (bits) {
7369223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
7379223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0x01;
7389223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7399223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
7409223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0x03;
7419223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7429223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
7439223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0x0f;
7449223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7459223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
7469223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0xff;
7479223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default: return -EINVAL;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
75061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bbtoffs = chip * (numblocks >> 2);
75261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
753596d74527a804418d88e1178c9d72aff5649e89cBrian Norris		to = ((loff_t)page) << this->page_shift;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7558b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Must we save the block contents? */
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->options & NAND_BBT_SAVECONTENT) {
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Make it block aligned */
758596d74527a804418d88e1178c9d72aff5649e89cBrian Norris			to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = 1 << this->bbt_erase_shift;
760329ad399a9b3adf52c90637b21ca029fcf7f8795Artem Bityutskiy			res = mtd_read(mtd, to, len, &retlen, buf);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res < 0) {
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (retlen != len) {
763d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					pr_info("nand_bbt: error reading block "
764d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris						"for writing the bad block table\n");
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return res;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
767d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				pr_warn("nand_bbt: ECC error while reading "
768d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					"block for writing bad block table\n");
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7709223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			/* Read oob data */
7717014568bad55c20b7ee4f439d78c9e875912d51fVitaly Wool			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
7728593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			ops.oobbuf = &buf[len];
773fd2819bbc92fc98bed5d612e4acbe16b6326f6bfArtem Bityutskiy			res = mtd_read_oob(mtd, to + mtd->writesize, &ops);
7747014568bad55c20b7ee4f439d78c9e875912d51fVitaly Wool			if (res < 0 || ops.oobretlen != ops.ooblen)
7759223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				goto outerr;
7769223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Calc the byte offset in the buffer */
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pageoffs = page - (int)(to >> this->page_shift);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs = pageoffs << this->page_shift;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Preset the bbt area with 0xff */
781596d74527a804418d88e1178c9d72aff5649e89cBrian Norris			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
7829223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			ooboffs = len + (pageoffs * mtd->oobsize);
7839223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
7847cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		} else if (td->options & NAND_BBT_NO_OOB) {
7857cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			ooboffs = 0;
7867cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			offs = td->len;
7878b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris			/* The version byte */
7887cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			if (td->options & NAND_BBT_VERSION)
7897cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				offs++;
7907cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/* Calc length */
791596d74527a804418d88e1178c9d72aff5649e89cBrian Norris			len = (size_t)(numblocks >> sft);
7927cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			len += offs;
7938b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris			/* Make it page aligned! */
7947cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			len = ALIGN(len, mtd->writesize);
7957cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/* Preset the buffer with 0xff */
7967cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			memset(buf, 0xff, len);
7977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/* Pattern is located at the begin of first page */
7987cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			memcpy(buf, td->pattern, td->len);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Calc length */
801596d74527a804418d88e1178c9d72aff5649e89cBrian Norris			len = (size_t)(numblocks >> sft);
8028b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris			/* Make it page aligned! */
803cda320915db00a07e5c4cdfc79806c3b80c0c7f2Sebastian Andrzej Siewior			len = ALIGN(len, mtd->writesize);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Preset the buffer with 0xff */
8059223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			memset(buf, 0xff, len +
8069223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			       (len >> this->page_shift)* mtd->oobsize);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs = 0;
8089223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			ooboffs = len;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Pattern is located in oob area of first page */
8109223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
81261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8139223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		if (td->options & NAND_BBT_VERSION)
8149223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			buf[ooboffs + td->veroffs] = td->version[chip];
8159223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
8168b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Walk through the memory table */
817e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		for (i = 0; i < numblocks;) {
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uint8_t dat;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dat = this->bbt[bbtoffs + (i >> 2)];
820e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			for (j = 0; j < 4; j++, i++) {
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int sftcnt = (i << (3 - sft)) & sftmsk;
8228b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				/* Do not store the reserved bbt blocks! */
8239223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				buf[offs + (i >> sft)] &=
8249223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner					~(msk[dat & 0x03] << sftcnt);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dat >>= 2;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
82861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
829e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		memset(&einfo, 0, sizeof(einfo));
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		einfo.mtd = mtd;
83169423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		einfo.addr = to;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		einfo.len = 1 << this->bbt_erase_shift;
833e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = nand_erase_nand(mtd, &einfo, 1);
8349223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		if (res < 0)
8359223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			goto outerr;
83661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8377cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		res = scan_write_bbt(mtd, to, len, buf,
8387cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				td->options & NAND_BBT_NO_OOB ? NULL :
8397cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				&buf[len]);
8409223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		if (res < 0)
8419223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			goto outerr;
8429223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
843d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
844d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			 (unsigned long long)to, td->version[chip]);
84561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Mark it as used */
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td->pages[chip] = page;
84861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8509223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
8519223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner outerr:
852d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris	pr_warn("nand_bbt: error while writing bad block table %d\n", res);
8539223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner	return res;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nand_memory_bbt - [GENERIC] create a memory based bad block table
8588b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
8598b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8618b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function creates a memory based bbt by scanning the device for
8628b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * manufacturer / software marked good / bad blocks.
8638b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
864e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
868171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy	bd->options &= ~NAND_BBT_SCANEMPTY;
8694bf63fcb83dc761853f69a77b15e47712689020bDavid Woodhouse	return create_bbt(mtd, this->buffers->databuf, bd, -1);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
873e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse * check_create - [GENERIC] create and write bbt(s) if necessary
8748b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
8758b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
8768b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8788b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function checks the results of the previous call to read_bbt and creates
8798b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
8808b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * for the chip/device. Update is necessary if one of the tables is missing or
8818b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the version nr. of one table is less than the other.
8828b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
883e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
885623978de362a5faeb18d8395fa86089650642626Brian Norris	int i, chips, writeops, create, chipsel, res, res2;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *td = this->bbt_td;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *md = this->bbt_md;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *rd, *rd2;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8918b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
89261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	if (td->options & NAND_BBT_PERCHIP)
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = this->numchips;
89461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	else
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = 1;
89661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeops = 0;
899b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris		create = 0;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd = NULL;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd2 = NULL;
902623978de362a5faeb18d8395fa86089650642626Brian Norris		res = res2 = 0;
9038b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Per chip or per device? */
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
9058b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Mirrored table available? */
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (md) {
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (td->pages[i] == -1 && md->pages[i] == -1) {
908b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris				create = 1;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 0x03;
910c5e8ef9c21a492f1e0436b350bbc3e916f93e506Brian Norris			} else if (td->pages[i] == -1) {
91161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner				rd = md;
912596d74527a804418d88e1178c9d72aff5649e89cBrian Norris				writeops = 0x01;
913c5e8ef9c21a492f1e0436b350bbc3e916f93e506Brian Norris			} else if (md->pages[i] == -1) {
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = td;
915596d74527a804418d88e1178c9d72aff5649e89cBrian Norris				writeops = 0x02;
916c5e8ef9c21a492f1e0436b350bbc3e916f93e506Brian Norris			} else if (td->version[i] == md->version[i]) {
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = td;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!(td->options & NAND_BBT_VERSION))
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rd2 = md;
920c5e8ef9c21a492f1e0436b350bbc3e916f93e506Brian Norris			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = td;
922596d74527a804418d88e1178c9d72aff5649e89cBrian Norris				writeops = 0x02;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = md;
925596d74527a804418d88e1178c9d72aff5649e89cBrian Norris				writeops = 0x01;
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (td->pages[i] == -1) {
929b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris				create = 1;
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 0x01;
931b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris			} else {
932b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris				rd = td;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
93561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
936b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris		if (create) {
937b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris			/* Create the bad block table by scanning the device? */
938b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris			if (!(td->options & NAND_BBT_CREATE))
939b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris				continue;
940b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris
941b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris			/* Create the table in memory by scanning the chip(s) */
942b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
943b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris				create_bbt(mtd, buf, bd, chipsel);
944b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris
945b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris			td->version[i] = 1;
946b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris			if (md)
947b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris				md->version[i] = 1;
948b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris		}
949b61bf5bbf619fc66ca866a27038da0b91cafb92dBrian Norris
9508b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Read back first? */
951623978de362a5faeb18d8395fa86089650642626Brian Norris		if (rd) {
952623978de362a5faeb18d8395fa86089650642626Brian Norris			res = read_abs_bbt(mtd, buf, rd, chipsel);
953623978de362a5faeb18d8395fa86089650642626Brian Norris			if (mtd_is_eccerr(res)) {
954623978de362a5faeb18d8395fa86089650642626Brian Norris				/* Mark table as invalid */
955623978de362a5faeb18d8395fa86089650642626Brian Norris				rd->pages[i] = -1;
956dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris				rd->version[i] = 0;
957623978de362a5faeb18d8395fa86089650642626Brian Norris				i--;
958623978de362a5faeb18d8395fa86089650642626Brian Norris				continue;
959623978de362a5faeb18d8395fa86089650642626Brian Norris			}
960623978de362a5faeb18d8395fa86089650642626Brian Norris		}
9618b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* If they weren't versioned, read both */
962623978de362a5faeb18d8395fa86089650642626Brian Norris		if (rd2) {
963623978de362a5faeb18d8395fa86089650642626Brian Norris			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
964623978de362a5faeb18d8395fa86089650642626Brian Norris			if (mtd_is_eccerr(res2)) {
965623978de362a5faeb18d8395fa86089650642626Brian Norris				/* Mark table as invalid */
966623978de362a5faeb18d8395fa86089650642626Brian Norris				rd2->pages[i] = -1;
967dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris				rd2->version[i] = 0;
968623978de362a5faeb18d8395fa86089650642626Brian Norris				i--;
969623978de362a5faeb18d8395fa86089650642626Brian Norris				continue;
970623978de362a5faeb18d8395fa86089650642626Brian Norris			}
971623978de362a5faeb18d8395fa86089650642626Brian Norris		}
972623978de362a5faeb18d8395fa86089650642626Brian Norris
973623978de362a5faeb18d8395fa86089650642626Brian Norris		/* Scrub the flash table(s)? */
974623978de362a5faeb18d8395fa86089650642626Brian Norris		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
975623978de362a5faeb18d8395fa86089650642626Brian Norris			writeops = 0x03;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
977dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris		/* Update version numbers before writing */
978dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris		if (md) {
979dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris			td->version[i] = max(td->version[i], md->version[i]);
980dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris			md->version[i] = td->version[i];
981dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris		}
982dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8Brian Norris
9838b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Write the bad block table to the device? */
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
985e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			res = write_bbt(mtd, buf, td, md, chipsel);
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res < 0)
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
98961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
9908b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Write the mirror bad block table to the device? */
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
992e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			res = write_bbt(mtd, buf, md, td, chipsel);
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res < 0)
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
99761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	return 0;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
100161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * mark_bbt_regions - [GENERIC] mark the bad block table regions
10028b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
10038b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: bad block table descriptor
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10058b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The bad block table regions are marked as "bad" to prevent accidental
10068b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * erasures / writes. The regions are identified by the mark 0x02.
10078b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1008e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, chips, block, nrblocks, update;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t oldval, newval;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10148b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = this->numchips;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = 1;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
102161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
102261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((td->options & NAND_BBT_ABSPAGE) ||
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    !(td->options & NAND_BBT_WRITE)) {
1026e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			if (td->pages[i] == -1)
1027e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse				continue;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
102961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner			block <<= 1;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oldval = this->bbt[(block >> 3)];
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			newval = oldval | (0x2 << (block & 0x06));
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt[(block >> 3)] = newval;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((oldval != newval) && td->reserved_block_code)
103469423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter				nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		update = 0;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->options & NAND_BBT_LASTBLOCK)
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block = ((i + 1) * nrblocks) - td->maxblocks;
104061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		else
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block = i * nrblocks;
104261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		block <<= 1;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < td->maxblocks; j++) {
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oldval = this->bbt[(block >> 3)];
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			newval = oldval | (0x2 << (block & 0x06));
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt[(block >> 3)] = newval;
1047e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			if (oldval != newval)
1048e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse				update = 1;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block += 2;
105061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
10518b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
10528b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * If we want reserved blocks to be recorded to flash, and some
10538b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * new ones have been marked, then we need to update the stored
10548b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * bbts.  This should only happen once.
10558b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 */
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (update && td->reserved_block_code)
105769423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter			nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
10627cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * verify_bbt_descr - verify the bad block description
10638b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
10648b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: the table to verify
10657cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior *
10667cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * This functions performs a few sanity checks on the bad block description
10677cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * table.
10687cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior */
10697cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
10707cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
10717cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	struct nand_chip *this = mtd->priv;
10727912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	u32 pattern_len;
10737912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	u32 bits;
10747cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 table_size;
10757cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10767cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!bd)
10777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return;
10787912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev
10797912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	pattern_len = bd->len;
10807912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	bits = bd->options & NAND_BBT_NRBITS_MSK;
10817912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev
1082a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
1083bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris			!(this->bbt_options & NAND_BBT_USE_FLASH));
10847cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	BUG_ON(!bits);
10857cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10867cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_VERSION)
10877cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		pattern_len++;
10887cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10897cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_NO_OOB) {
1090bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
1091a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
10927cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		BUG_ON(bd->offs);
10937cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		if (bd->options & NAND_BBT_VERSION)
10947cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			BUG_ON(bd->veroffs != bd->len);
10957cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
10967cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	}
10977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10987cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_PERCHIP)
10997cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		table_size = this->chipsize >> this->bbt_erase_shift;
11007cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	else
11017cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		table_size = mtd->size >> this->bbt_erase_shift;
11027cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	table_size >>= 3;
11037cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	table_size *= bits;
11047cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_NO_OOB)
11057cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		table_size += pattern_len;
11067cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	BUG_ON(table_size > (1 << this->bbt_erase_shift));
11077cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
11087cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
11097cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior/**
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
11118b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
11128b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11148b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function checks, if a bad block table(s) is/are already available. If
11158b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * not it scans the device for manufacturer marked good / bad blocks and writes
11168b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the bad block table(s) to the selected place.
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11188b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The bad block table memory is allocated here. It must be freed by calling
11198b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the nand_free_bbt function.
11208b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1121e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len, res = 0;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *buf;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *td = this->bbt_td;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *md = this->bbt_md;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = mtd->size >> (this->bbt_erase_shift + 2);
11308b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/*
11318b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * Allocate memory (2bit per block) and clear the memory bad block
11328b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * table.
11338b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 */
113495b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan	this->bbt = kzalloc(len, GFP_KERNEL);
11350870066d7e6c85bbe37741137e4c4731501a98e0Brian Norris	if (!this->bbt)
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11388b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/*
11398b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * If no primary table decriptor is given, scan the device to build a
11408b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * memory based bad block table.
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1142eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	if (!td) {
1143eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		if ((res = nand_memory_bbt(mtd, bd))) {
1144d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
1145e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			kfree(this->bbt);
1146eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy			this->bbt = NULL;
1147eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		}
1148eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		return res;
1149eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	}
11507cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	verify_bbt_descr(mtd, td);
11517cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	verify_bbt_descr(mtd, md);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allocate a temporary buffer for one eraseblock incl. oob */
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (1 << this->bbt_erase_shift);
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += (len >> this->page_shift) * mtd->oobsize;
1156c3f8abf481c2d2b221b028f7369bc6dd39a9590eDavid Woodhouse	buf = vmalloc(len);
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
1158e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		kfree(this->bbt);
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		this->bbt = NULL;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
116261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
11638b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Is the bbt at a given page? */
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_ABSPAGE) {
1165e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = read_abs_bbts(mtd, buf, td, md);
116661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	} else {
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Search the bad block table using a pattern in oob */
1168e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = search_read_bbts(mtd, buf, td, md);
116961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	if (res)
1172e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = check_create(mtd, buf, bd);
117361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Prevent the bbt regions from erasing / writing */
1175e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	mark_bbt_region(mtd, td);
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md)
1177e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		mark_bbt_region(mtd, md);
117861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
1179e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	vfree(buf);
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
118461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * nand_update_bbt - [NAND Interface] update bad block table(s)
11858b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
11868b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @offs: the offset of the newly marked block
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11888b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function updates the bad block table(s).
11898b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1190e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_update_bbt(struct mtd_info *mtd, loff_t offs)
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
11931196ac5a9969f180c67e9a4454384250ab034452Brian Norris	int len, res = 0;
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chip, chipsel;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *buf;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *td = this->bbt_td;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *md = this->bbt_md;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!this->bbt || !td)
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allocate a temporary buffer for one eraseblock incl. oob */
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (1 << this->bbt_erase_shift);
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += (len >> this->page_shift) * mtd->oobsize;
1205e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	buf = kmalloc(len, GFP_KERNEL);
12060870066d7e6c85bbe37741137e4c4731501a98e0Brian Norris	if (!buf)
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12098b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
1211e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		chip = (int)(offs >> this->chip_shift);
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chipsel = chip;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip = 0;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chipsel = -1;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	td->version[chip]++;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md)
122061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		md->version[chip]++;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12228b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Write the bad block table to the device? */
12231196ac5a9969f180c67e9a4454384250ab034452Brian Norris	if (td->options & NAND_BBT_WRITE) {
1224e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = write_bbt(mtd, buf, td, md, chipsel);
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res < 0)
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12288b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Write the mirror bad block table to the device? */
12291196ac5a9969f180c67e9a4454384250ab034452Brian Norris	if (md && (md->options & NAND_BBT_WRITE)) {
1230e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = write_bbt(mtd, buf, md, td, chipsel);
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1233e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse out:
1234e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	kfree(buf);
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12388b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/*
12398b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Define some generic bad / good block scan pattern which are used
12408b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * while scanning a device for factory marked good / bad blocks.
12418b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t scan_ff_pattern[] = { 0xff, 0xff };
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_bbt_descr agand_flashbased = {
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.offs = 0x20,
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.len = 6,
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pattern = scan_agand_pattern
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12537854d3f7495b11be1570cd3e2318674d8f9ed797Brian Norris/* Generic flash bbt descriptors */
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_bbt_descr bbt_main_descr = {
125861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.offs =	8,
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.len = 4,
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.veroffs = 12,
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.maxblocks = 4,
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pattern = bbt_pattern
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_bbt_descr bbt_mirror_descr = {
126861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.offs =	8,
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.len = 4,
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.veroffs = 12,
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.maxblocks = 4,
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pattern = mirror_pattern
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic struct nand_bbt_descr bbt_main_no_bbt_descr = {
12787cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12797cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
12807cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_NO_OOB,
12817cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.len = 4,
12827cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.veroffs = 4,
12837cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.maxblocks = 4,
12847cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.pattern = bbt_pattern
12857cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior};
12867cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
12877cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
12887cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12897cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
12907cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_NO_OOB,
12917cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.len = 4,
12927cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.veroffs = 4,
12937cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.maxblocks = 4,
12947cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.pattern = mirror_pattern
12957cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior};
12967cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
1297752ed6c5f8c0ee182219ff8682f5a98e47ee866fBrian Norris#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
129858373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris/**
1299752ed6c5f8c0ee182219ff8682f5a98e47ee866fBrian Norris * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
13008b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @this: NAND chip to create descriptor for
130158373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris *
130258373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris * This function allocates and initializes a nand_bbt_descr for BBM detection
1303752ed6c5f8c0ee182219ff8682f5a98e47ee866fBrian Norris * based on the properties of @this. The new descriptor is stored in
130458373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
130558373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris * passed to this function.
130658373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris */
1307752ed6c5f8c0ee182219ff8682f5a98e47ee866fBrian Norrisstatic int nand_create_badblock_pattern(struct nand_chip *this)
130858373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris{
130958373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	struct nand_bbt_descr *bd;
131058373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	if (this->badblock_pattern) {
1311752ed6c5f8c0ee182219ff8682f5a98e47ee866fBrian Norris		pr_warn("Bad block pattern already allocated; not replacing\n");
131258373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		return -EINVAL;
131358373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	}
131458373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
13150870066d7e6c85bbe37741137e4c4731501a98e0Brian Norris	if (!bd)
131658373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		return -ENOMEM;
1317752ed6c5f8c0ee182219ff8682f5a98e47ee866fBrian Norris	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
131858373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->offs = this->badblockpos;
131958373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
132058373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->pattern = scan_ff_pattern;
132158373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->options |= NAND_BBT_DYNAMICSTRUCT;
132258373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	this->badblock_pattern = bd;
132358373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	return 0;
132458373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris}
132558373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
132761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
13288b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13308b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * This function selects the default bad block table support for the device and
13318b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * calls the nand_scan_bbt function.
13328b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1333e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_default_bbt(struct mtd_info *mtd)
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
133661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
13378b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/*
13388b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * Default for AG-AND. We must use a flash based bad block table as the
13398b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * devices have factory marked _good_ blocks. Erasing those blocks
13408b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * leads to loss of the good / bad information, so we _must_ store this
13418b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * information in a good / bad table during startup.
1342e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	 */
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (this->options & NAND_IS_AND) {
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Use the default pattern descriptors */
134561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		if (!this->bbt_td) {
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt_td = &bbt_main_descr;
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt_md = &bbt_mirror_descr;
134861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
1349bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris		this->bbt_options |= NAND_BBT_USE_FLASH;
1350e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return nand_scan_bbt(mtd, &agand_flashbased);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
135261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
13538b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Is a flash based bad block table requested? */
1354bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris	if (this->bbt_options & NAND_BBT_USE_FLASH) {
135561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		/* Use the default pattern descriptors */
135661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		if (!this->bbt_td) {
1357a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris			if (this->bbt_options & NAND_BBT_NO_OOB) {
13587cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_td = &bbt_main_no_bbt_descr;
13597cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_md = &bbt_mirror_no_bbt_descr;
13607cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			} else {
13617cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_td = &bbt_main_descr;
13627cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_md = &bbt_mirror_descr;
13637cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			}
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		this->bbt_td = NULL;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		this->bbt_md = NULL;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1369a2f812df0b3d467db2ae5e3be38c36ff692ff99fBrian Norris
1370a2f812df0b3d467db2ae5e3be38c36ff692ff99fBrian Norris	if (!this->badblock_pattern)
1371752ed6c5f8c0ee182219ff8682f5a98e47ee866fBrian Norris		nand_create_badblock_pattern(this);
1372a2f812df0b3d467db2ae5e3be38c36ff692ff99fBrian Norris
1373e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	return nand_scan_bbt(mtd, this->badblock_pattern);
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
137761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * nand_isbad_bbt - [NAND Interface] Check if a block is bad
13788b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
13798b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @offs: offset in the device
13808b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @allowbbt: allow access to bad block table region
13818b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1382e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int block;
1386e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	uint8_t res;
138761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get block number * 2 */
1389e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	block = (int)(offs >> (this->bbt_erase_shift - 1));
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1392289c05222172b51401dbbb017115655f241d94abBrian Norris	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
1393289c05222172b51401dbbb017115655f241d94abBrian Norris			"(block %d) 0x%02x\n",
1394289c05222172b51401dbbb017115655f241d94abBrian Norris			(unsigned int)offs, block >> 1, res);
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch ((int)res) {
1397e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	case 0x00:
1398e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return 0;
1399e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	case 0x01:
1400e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return 1;
1401e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	case 0x02:
1402e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return allowbbt ? 0 : 1;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1407e0c7d7675331140e5186d2d1a0efce1d3877d379David WoodhouseEXPORT_SYMBOL(nand_scan_bbt);
1408e0c7d7675331140e5186d2d1a0efce1d3877d379David WoodhouseEXPORT_SYMBOL(nand_default_bbt);
1409