nand_bbt.c revision afa17de262633603dd65f89e9370f48e56b8c557
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>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
717cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
727cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
737cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	int ret;
747cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
757cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	ret = memcmp(buf, td->pattern, td->len);
767cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!ret)
777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return ret;
787cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	return -1;
797cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
807cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
8161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner/**
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check_pattern - [GENERIC] check if a pattern is in the buffer
838b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: the buffer to search
848b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @len: the length of buffer to search
858b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @paglen: the pagelength
868b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: search pattern descriptor
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
888b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Check for a pattern at the given place. Used to search bad block tables and
898b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
908b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * all bytes except the pattern area contain 0xff.
918b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
92e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
94171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy	int i, end = 0;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *p = buf;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_NO_OOB)
987cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return check_pattern_no_oob(buf, td);
997cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
100c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	end = paglen + td->offs;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_SCANEMPTY) {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < end; i++) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (p[i] != 0xff)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -1;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
107c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	p += end;
10861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Compare the pattern */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < td->len; i++) {
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (p[i] != td->pattern[i])
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -1;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_SCANEMPTY) {
116171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		p += td->len;
117171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		end += td->len;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = end; i < len; i++) {
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (*p++ != 0xff)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -1;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner/**
127c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner * check_short_pattern - [GENERIC] check if a pattern is in the buffer
1288b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: the buffer to search
1298b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td:	search pattern descriptor
130c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner *
1318b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Check for a pattern at the given place. Used to search bad block tables and
1328b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * good / bad block identifiers. Same as check_pattern, but no optional empty
1338b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * check.
1348b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
135e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
136c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner{
137c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	int i;
138c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	uint8_t *p = buf;
139c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner
140c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	/* Compare the pattern */
141c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	for (i = 0; i < td->len; i++) {
14219870da7ea2fc483bf73a189046a430fd9b01391Thomas Gleixner		if (p[td->offs + i] != td->pattern[i])
143c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner			return -1;
144c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	}
145c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner	return 0;
146c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner}
147c9e0536523f5191395d62f6c84d007e6ffd38d33Thomas Gleixner
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1497cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * add_marker_len - compute the length of the marker in data area
1508b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: BBT descriptor used for computation
1517cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior *
1527854d3f7495b11be1570cd3e2318674d8f9ed797Brian Norris * The length will be 0 if the marker is located in OOB area.
1537cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior */
1547cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic u32 add_marker_len(struct nand_bbt_descr *td)
1557cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
1567cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 len;
1577cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
1587cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!(td->options & NAND_BBT_NO_OOB))
1597cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return 0;
1607cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
1617cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	len = td->len;
1627cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_VERSION)
1637cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		len++;
1647cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	return len;
1657cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
1667cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
1677cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior/**
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read_bbt - [GENERIC] Read the bad block table starting from page
1698b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
1708b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
1718b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @page: the starting page
1728b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @num: the number of bbt descriptors to read
1737854d3f7495b11be1570cd3e2318674d8f9ed797Brian Norris * @td: the bbt describtion table
1748b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @offs: offset in the memory table
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the bad block table starting from page.
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
178e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
179df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior		struct nand_bbt_descr *td, int offs)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res, i, j, act = 0;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t retlen, len, totlen;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loff_t from;
185df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior	int bits = td->options & NAND_BBT_NRBITS_MSK;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t msk = (uint8_t) ((1 << bits) - 1);
1877cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 marker_len;
188df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior	int reserved_block_code = td->reserved_block_code;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	totlen = (num * bits) >> 3;
1917cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	marker_len = add_marker_len(td);
192e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	from = ((loff_t) page) << this->page_shift;
19361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (totlen) {
195e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
1967cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		if (marker_len) {
1977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/*
1987cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 * In case the BBT marker is not in the OOB area it
1997cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 * will be just in the first page.
2007cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 */
2017cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			len -= marker_len;
2027cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			from += marker_len;
2037cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			marker_len = 0;
2047cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		}
2059223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		res = mtd->read(mtd, from, len, &retlen, buf);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res < 0) {
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (retlen != len) {
208d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				pr_info("nand_bbt: error reading bad block table\n");
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2119a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris			pr_warn("nand_bbt: ECC error while reading bad block table\n");
21261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Analyse data */
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < len; i++) {
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uint8_t dat = buf[i];
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (j = 0; j < 8; j += bits, act += 2) {
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				uint8_t tmp = (dat >> j) & msk;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tmp == msk)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
221e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse				if (reserved_block_code && (tmp == reserved_block_code)) {
222d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
223d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris						 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
225f1a28c02843efcfcc41982149880bac3ac180234Thomas Gleixner					mtd->ecc_stats.bbtblocks++;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2288b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				/*
2298b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				 * Leave it for now, if it's matured we can
230a0f5080ecc1c75f9c08591d9b0f48451e7ac8ddcBrian Norris				 * move this message to pr_debug.
2318b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				 */
232d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
233d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
2348b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				/* Factory marked bad or worn out? */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (tmp == 0)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
239f1a28c02843efcfcc41982149880bac3ac180234Thomas Gleixner				mtd->ecc_stats.badblocks++;
24061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner			}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		totlen -= len;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from += len;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
2508b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
2518b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
2528b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
2538b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @chip: read the table for a specific chip, -1 read all chips; aplies only if
2548b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris *        NAND_BBT_PERCHIP option is set
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2568b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Read the bad block table for all chips starting at a given page. We assume
2578b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * that the bbt bits are in consecutive order.
2588b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
259e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res = 0, i;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int offs = 0;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < this->numchips; i++) {
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip == -1 || chip == i)
268df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior				res = read_bbt(mtd, buf, td->pages[i],
269df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior					this->chipsize >> this->bbt_erase_shift,
270df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior					td, offs);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res)
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs += this->chipsize >> (this->bbt_erase_shift + 2);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
276df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior		res = read_bbt(mtd, buf, td->pages[0],
277df5b4e343c52fcdc54db3f9d07068c98cda6007bSebastian Andrzej Siewior				mtd->size >> this->bbt_erase_shift, td, 0);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res)
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return res;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2848b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* BBT marker is in the first page, no OOB */
2857cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
2867cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 struct nand_bbt_descr *td)
2877cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
2887cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	size_t retlen;
2897cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	size_t len;
2907cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
2917cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	len = td->len;
2927cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_VERSION)
2937cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		len++;
2947cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
2957cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	return mtd->read(mtd, offs, len, &retlen, buf);
2967cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
2977cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
2988b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan read raw data from flash */
2997cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
3008593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			 size_t len)
3018593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
3028593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
303b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	int res;
3048593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3050612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_RAW;
3068593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
3078593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
3088593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
309b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	while (len > 0) {
310105513cc4a25522f959788371bd612f987d4d184Brian Norris		ops.datbuf = buf;
311105513cc4a25522f959788371bd612f987d4d184Brian Norris		ops.len = min(len, (size_t)mtd->writesize);
312105513cc4a25522f959788371bd612f987d4d184Brian Norris		ops.oobbuf = buf + ops.len;
313903cd06cd6ece7f9050a3ad5b03e0b76be2882ffBrian Norris
314105513cc4a25522f959788371bd612f987d4d184Brian Norris		res = mtd->read_oob(mtd, offs, &ops);
315b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky
316afa17de262633603dd65f89e9370f48e56b8c557Brian Norris		if (res)
317105513cc4a25522f959788371bd612f987d4d184Brian Norris			return res;
318b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky
319b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky		buf += mtd->oobsize + mtd->writesize;
320b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky		len -= mtd->writesize;
321b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	}
322b64d39d8b03fea88417d53715ccbebf71d4dcc9fMaxim Levitsky	return 0;
3238593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
3248593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3257cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
3267cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			 size_t len, struct nand_bbt_descr *td)
3277cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
3287cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (td->options & NAND_BBT_NO_OOB)
3297cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return scan_read_raw_data(mtd, buf, offs, td);
3307cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	else
3317cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return scan_read_raw_oob(mtd, buf, offs, len);
3327cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
3337cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
3348b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan write data with oob to flash */
3358593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
3368593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			  uint8_t *buf, uint8_t *oob)
3378593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
3388593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
3398593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3400612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_PLACE_OOB;
3418593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
3428593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
3438593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.datbuf = buf;
3448593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.oobbuf = oob;
3458593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.len = len;
3468593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3478593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	return mtd->write_oob(mtd, offs, &ops);
3488593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
3498593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
3507cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
3517cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
3527cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 ver_offs = td->veroffs;
3537cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
3547cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!(td->options & NAND_BBT_NO_OOB))
3557cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		ver_offs += mtd->writesize;
3567cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	return ver_offs;
3577cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
3587cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
3618b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
3628b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
3638b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
3648b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @md:	descriptor for the bad block table mirror
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3668b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Read the bad block table(s) for all chips starting at a given page. We
3678b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * assume that the bbt bits are in consecutive order.
3688b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
3698593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
3708593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			 struct nand_bbt_descr *td, struct nand_bbt_descr *md)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	/* Read the primary version, if available */
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_VERSION) {
37669423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
3777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			      mtd->writesize, td);
3787cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
3799a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris		pr_info("Bad block table at page %d, version 0x%02X\n",
380d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			 td->pages[0], td->version[0]);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	/* Read the mirror version, if available */
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md && (md->options & NAND_BBT_VERSION)) {
38569423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
3867cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			      mtd->writesize, td);
3877cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
3889a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris		pr_info("Bad block table at page %d, version 0x%02X\n",
389d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			 md->pages[0], md->version[0]);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3948b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan a given block full */
3958593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
3968593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			   loff_t offs, uint8_t *buf, size_t readlen,
3978593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			   int scanlen, int len)
3988593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
3998593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int ret, j;
4008593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4017cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	ret = scan_read_raw_oob(mtd, buf, offs, readlen);
402afa17de262633603dd65f89e9370f48e56b8c557Brian Norris	/* Ignore ECC errors when checking for BBM */
403afa17de262633603dd65f89e9370f48e56b8c557Brian Norris	if (ret && ret != -EUCLEAN && ret != -EBADMSG)
4048593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		return ret;
4058593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4068593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	for (j = 0; j < len; j++, buf += scanlen) {
4078593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (check_pattern(buf, scanlen, mtd->writesize, bd))
4088593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return 1;
4098593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	}
4108593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	return 0;
4118593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
4128593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4138b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/* Scan a given block partially */
4148593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
4158593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			   loff_t offs, uint8_t *buf, int len)
4168593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner{
4178593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
4188593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int j, ret;
4198593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4208593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
4218593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.oobbuf = buf;
4228593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
4238593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.datbuf = NULL;
4240612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_PLACE_OOB;
4258593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4268593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	for (j = 0; j < len; j++) {
4278593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		/*
4288b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * Read the full oob until read_oob is fixed to handle single
4298b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * byte reads for 16 bit buswidth.
4308593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		 */
4318593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		ret = mtd->read_oob(mtd, offs, &ops);
432903cd06cd6ece7f9050a3ad5b03e0b76be2882ffBrian Norris		/* Ignore ECC errors when checking for BBM */
433903cd06cd6ece7f9050a3ad5b03e0b76be2882ffBrian Norris		if (ret && ret != -EUCLEAN && ret != -EBADMSG)
4348593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return ret;
4358593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4368593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (check_short_pattern(buf, bd))
4378593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return 1;
4388593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4398593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		offs += mtd->writesize;
4408593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	}
4418593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	return 0;
4428593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner}
4438593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * create_bbt - [GENERIC] Create a bad block table by scanning the device
4468b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
4478b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
4488b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
4498b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @chip: create the table for a specific chip, -1 read all chips; applies only
4508b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris *        if NAND_BBT_PERCHIP option is set
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4528b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Create a bad block table by scanning the device for the given good/bad block
4538b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * identify pattern.
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4558593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixnerstatic int create_bbt(struct mtd_info *mtd, uint8_t *buf,
4568593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct nand_bbt_descr *bd, int chip)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
4598593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int i, numblocks, len, scanlen;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int startblock;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loff_t from;
4628593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	size_t readlen;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4649a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris	pr_info("Scanning device for bad blocks\n");
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bd->options & NAND_BBT_SCANALLPAGES)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = 1 << (this->bbt_erase_shift - this->page_shift);
46858373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	else if (bd->options & NAND_BBT_SCAN2NDPAGE)
46958373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		len = 2;
47058373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	else
47158373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		len = 1;
472171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy
473171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy	if (!(bd->options & NAND_BBT_SCANEMPTY)) {
474171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		/* We need only read few bytes from the OOB area */
4758593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		scanlen = 0;
476eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		readlen = bd->len;
477eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	} else {
478171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy		/* Full page content should be read */
47928318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel		scanlen = mtd->writesize + mtd->oobsize;
48028318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel		readlen = len * mtd->writesize;
481eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip == -1) {
4848b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
4858b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * Note that numblocks is 2 * (real numblocks) here, see i+=2
4868b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * below as it makes shifting and masking less painful
4878b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		numblocks = mtd->size >> (this->bbt_erase_shift - 1);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock = 0;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from = 0;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chip >= this->numchips) {
4939a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
494e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			       chip + 1, this->numchips);
495171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy			return -EINVAL;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock = chip * numblocks;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		numblocks += startblock;
50069423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		from = (loff_t)startblock << (this->bbt_erase_shift - 1);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
50261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5035fb1549dfc40f3b589dae560ea21535cdc5f64e0Brian Norris	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
504b60b08b02ca8d9575985ae6711bd656dd67e9039Kevin Cernekee		from += mtd->erasesize - (mtd->writesize * len);
505b60b08b02ca8d9575985ae6711bd656dd67e9039Kevin Cernekee
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = startblock; i < numblocks;) {
507eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		int ret;
50861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5097cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		BUG_ON(bd->options & NAND_BBT_NO_OOB);
5107cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
5118593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (bd->options & NAND_BBT_SCANALLPAGES)
5128593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			ret = scan_block_full(mtd, bd, from, buf, readlen,
5138593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner					      scanlen, len);
5148593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		else
5158593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			ret = scan_block_fast(mtd, bd, from, buf, len);
5168593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5178593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (ret < 0)
5188593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			return ret;
5198593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5208593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner		if (ret) {
5218593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			this->bbt[i >> 3] |= 0x03 << (i & 0x6);
5229a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris			pr_warn("Bad eraseblock %d at 0x%012llx\n",
523d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				i >> 1, (unsigned long long)from);
524f1a28c02843efcfcc41982149880bac3ac180234Thomas Gleixner			mtd->ecc_stats.badblocks++;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5268593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i += 2;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		from += (1 << this->bbt_erase_shift);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
530eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	return 0;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search_bbt - [GENERIC] scan the device for a specific bad block table
5358b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
5368b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
5378b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5398b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Read the bad block table by searching for a given ident pattern. Search is
5408b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * preformed either from the beginning up or from the end of the device
5418b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * downwards. The search starts always at the start of a block. If the option
5428b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
5438b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the bad block information of this chip. This is necessary to provide support
5448b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * for certain DOC devices.
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5468b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The bbt ident pattern resides in the oob area of the first page in a block.
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
548e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, chips;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bits, startblock, block, dir;
55328318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel	int scanlen = mtd->writesize + mtd->oobsize;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bbtblocks;
5558593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	int blocktopage = this->bbt_erase_shift - this->page_shift;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5578b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Search direction top -> down? */
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_LASTBLOCK) {
559e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		startblock = (mtd->size >> this->bbt_erase_shift) - 1;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dir = -1;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
56261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		startblock = 0;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dir = 1;
56461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
56561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5668b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = this->numchips;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bbtblocks = this->chipsize >> this->bbt_erase_shift;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock &= bbtblocks - 1;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = 1;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bbtblocks = mtd->size >> this->bbt_erase_shift;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
57561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Number of bits for each erase block in the bbt */
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bits = td->options & NAND_BBT_NRBITS_MSK;
57861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset version information */
58161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		td->version[i] = 0;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td->pages[i] = -1;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Scan the maximum number of blocks */
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (block = 0; block < td->maxblocks; block++) {
5858593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int actblock = startblock + dir * block;
58769423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
5888593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Read first page */
5907cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			scan_read_raw(mtd, buf, offs, mtd->writesize, td);
59128318776a80bc3261f9af91ef79e6e38bb9f5becJoern Engel			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
5928593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner				td->pages[i] = actblock << blocktopage;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (td->options & NAND_BBT_VERSION) {
5947cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior					offs = bbt_get_ver_offs(mtd, td);
5957cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior					td->version[i] = buf[offs];
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		startblock += this->chipsize >> this->bbt_erase_shift;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check, if we found a bbt for each requested chip */
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->pages[i] == -1)
6059a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris			pr_warn("Bad block table not found for chip %d\n", i);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
607d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			pr_info("Bad block table found at page %d, version "
608d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				 "0x%02X\n", td->pages[i], td->version[i]);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
61061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	return 0;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search_read_bbts - [GENERIC] scan the device for bad block table(s)
6158b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
6168b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
6178b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
6188b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @md: descriptor for the bad block table mirror
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6208b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Search and read the bad block table(s).
6218b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
622e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Search the primary table */
625e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	search_bbt(mtd, buf, td);
62661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Search the mirror table */
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md)
629e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		search_bbt(mtd, buf, md);
63061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Force result check */
63261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	return 1;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner/**
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write_bbt - [GENERIC] (Re)write the bad block table
6378b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
6388b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
6398b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: descriptor for the bad block table
6408b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @md: descriptor for the bad block table mirror
6418b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @chipsel: selector for a specific chip, -1 for all
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6438b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * (Re)write the bad block table.
6448b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
645e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int write_bbt(struct mtd_info *mtd, uint8_t *buf,
6469223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
6479223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		     int chipsel)
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct erase_info einfo;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, res, chip = 0;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
6539223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner	int nrchips, bbtoffs, pageoffs, ooboffs;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t msk[4];
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t rcode = td->reserved_block_code;
6568593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	size_t retlen, len = 0;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loff_t to;
6588593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	struct mtd_oob_ops ops;
6598593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner
6608593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooblen = mtd->oobsize;
6618593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.ooboffs = 0;
6628593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner	ops.datbuf = NULL;
6630612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris	ops.mode = MTD_OPS_PLACE_OOB;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rcode)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rcode = 0xff;
6678b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Write bad block table per chip rather than per device? */
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
669e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
6708b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Full device write or specific chip? */
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chipsel == -1) {
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nrchips = this->numchips;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nrchips = chipsel + 1;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			chip = chipsel;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
678e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrchips = 1;
68061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
68161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Loop through the chips */
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; chip < nrchips; chip++) {
6848b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
6858b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * There was already a version of the table, reuse the page
68661b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		 * This applies for absolute placement too, as we have the
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * page nr. in td->pages.
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->pages[chip] != -1) {
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			page = td->pages[chip];
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto write;
69261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6948b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
6958b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * Automatic placement of the bad block table. Search direction
6968b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * top -> down?
6978b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 */
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->options & NAND_BBT_LASTBLOCK) {
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			startblock = numblocks * (chip + 1) - 1;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dir = -1;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			startblock = chip * numblocks;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dir = 1;
70461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < td->maxblocks; i++) {
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int block = startblock + dir * i;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check, if the block is bad */
7099223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			switch ((this->bbt[block >> 2] >>
7109223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				 (2 * (block & 0x03))) & 0x03) {
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 0x01:
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 0x03:
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7159223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			page = block <<
7169223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				(this->bbt_erase_shift - this->page_shift);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Check, if the block is used by the mirror table */
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!md || md->pages[chip] != page)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto write;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7219a4d4d69018e7b719ba58fa30fcdd60e547776b8Brian Norris		pr_err("No space left to write bad block table\n");
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOSPC;
723e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	write:
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Set up shift count and masks for the flash table */
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bits = td->options & NAND_BBT_NRBITS_MSK;
7279223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		msk[2] = ~rcode;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (bits) {
7299223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
7309223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0x01;
7319223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7329223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
7339223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0x03;
7349223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7359223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
7369223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0x0f;
7379223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7389223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
7399223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			msk[3] = 0xff;
7409223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			break;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default: return -EINVAL;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
74361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bbtoffs = chip * (numblocks >> 2);
74561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to = ((loff_t) page) << this->page_shift;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7488b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Must we save the block contents? */
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->options & NAND_BBT_SAVECONTENT) {
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Make it block aligned */
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = 1 << this->bbt_erase_shift;
7539223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			res = mtd->read(mtd, to, len, &retlen, buf);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res < 0) {
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (retlen != len) {
756d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					pr_info("nand_bbt: error reading block "
757d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris						"for writing the bad block table\n");
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return res;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
760d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris				pr_warn("nand_bbt: ECC error while reading "
761d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris					"block for writing bad block table\n");
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7639223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			/* Read oob data */
7647014568bad55c20b7ee4f439d78c9e875912d51fVitaly Wool			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
7658593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			ops.oobbuf = &buf[len];
7668593fbc68b0df1168995de76d1af38eb62fd6b62Thomas Gleixner			res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
7677014568bad55c20b7ee4f439d78c9e875912d51fVitaly Wool			if (res < 0 || ops.oobretlen != ops.ooblen)
7689223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				goto outerr;
7699223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Calc the byte offset in the buffer */
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pageoffs = page - (int)(to >> this->page_shift);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs = pageoffs << this->page_shift;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Preset the bbt area with 0xff */
774e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
7759223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			ooboffs = len + (pageoffs * mtd->oobsize);
7769223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
7777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		} else if (td->options & NAND_BBT_NO_OOB) {
7787cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			ooboffs = 0;
7797cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			offs = td->len;
7808b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris			/* The version byte */
7817cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			if (td->options & NAND_BBT_VERSION)
7827cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				offs++;
7837cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/* Calc length */
7847cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			len = (size_t) (numblocks >> sft);
7857cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			len += offs;
7868b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris			/* Make it page aligned! */
7877cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			len = ALIGN(len, mtd->writesize);
7887cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/* Preset the buffer with 0xff */
7897cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			memset(buf, 0xff, len);
7907cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			/* Pattern is located at the begin of first page */
7917cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			memcpy(buf, td->pattern, td->len);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Calc length */
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = (size_t) (numblocks >> sft);
7958b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris			/* Make it page aligned! */
796cda320915db00a07e5c4cdfc79806c3b80c0c7f2Sebastian Andrzej Siewior			len = ALIGN(len, mtd->writesize);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Preset the buffer with 0xff */
7989223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			memset(buf, 0xff, len +
7999223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			       (len >> this->page_shift)* mtd->oobsize);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offs = 0;
8019223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			ooboffs = len;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Pattern is located in oob area of first page */
8039223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
80561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8069223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		if (td->options & NAND_BBT_VERSION)
8079223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			buf[ooboffs + td->veroffs] = td->version[chip];
8089223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
8098b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Walk through the memory table */
810e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		for (i = 0; i < numblocks;) {
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			uint8_t dat;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dat = this->bbt[bbtoffs + (i >> 2)];
813e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			for (j = 0; j < 4; j++, i++) {
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int sftcnt = (i << (3 - sft)) & sftmsk;
8158b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris				/* Do not store the reserved bbt blocks! */
8169223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner				buf[offs + (i >> sft)] &=
8179223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner					~(msk[dat & 0x03] << sftcnt);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dat >>= 2;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
82161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
822e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		memset(&einfo, 0, sizeof(einfo));
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		einfo.mtd = mtd;
82469423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter		einfo.addr = to;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		einfo.len = 1 << this->bbt_erase_shift;
826e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = nand_erase_nand(mtd, &einfo, 1);
8279223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		if (res < 0)
8289223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			goto outerr;
82961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8307cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		res = scan_write_bbt(mtd, to, len, buf,
8317cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				td->options & NAND_BBT_NO_OOB ? NULL :
8327cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				&buf[len]);
8339223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner		if (res < 0)
8349223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner			goto outerr;
8359223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
836d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
837d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			 (unsigned long long)to, td->version[chip]);
83861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Mark it as used */
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td->pages[chip] = page;
84161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8439223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner
8449223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner outerr:
845d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris	pr_warn("nand_bbt: error while writing bad block table %d\n", res);
8469223a456da8ed357bf7e0b128c853e2c8bd54614Thomas Gleixner	return res;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nand_memory_bbt - [GENERIC] create a memory based bad block table
8518b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
8528b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8548b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function creates a memory based bbt by scanning the device for
8558b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * manufacturer / software marked good / bad blocks.
8568b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
857e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861171650af9cd847964cf69b6bab9009631283293fArtem B. Bityuckiy	bd->options &= ~NAND_BBT_SCANEMPTY;
8624bf63fcb83dc761853f69a77b15e47712689020bDavid Woodhouse	return create_bbt(mtd, this->buffers->databuf, bd, -1);
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
866e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse * check_create - [GENERIC] create and write bbt(s) if necessary
8678b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
8688b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @buf: temporary buffer
8698b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8718b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function checks the results of the previous call to read_bbt and creates
8728b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
8738b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * for the chip/device. Update is necessary if one of the tables is missing or
8748b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the version nr. of one table is less than the other.
8758b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
876e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, chips, writeops, chipsel, res;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *td = this->bbt_td;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *md = this->bbt_md;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *rd, *rd2;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8848b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
88561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	if (td->options & NAND_BBT_PERCHIP)
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = this->numchips;
88761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	else
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = 1;
88961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writeops = 0;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd = NULL;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd2 = NULL;
8948b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Per chip or per device? */
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
8968b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Mirrored table available? */
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (md) {
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (td->pages[i] == -1 && md->pages[i] == -1) {
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 0x03;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto create;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (td->pages[i] == -1) {
90461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner				rd = md;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				td->version[i] = md->version[i];
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 1;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto writecheck;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (md->pages[i] == -1) {
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = td;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				md->version[i] = td->version[i];
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 2;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto writecheck;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (td->version[i] == md->version[i]) {
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = td;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!(td->options & NAND_BBT_VERSION))
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rd2 = md;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto writecheck;
92261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner			}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (((int8_t) (td->version[i] - md->version[i])) > 0) {
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = td;
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				md->version[i] = td->version[i];
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 2;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rd = md;
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				td->version[i] = md->version[i];
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 1;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto writecheck;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (td->pages[i] == -1) {
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				writeops = 0x01;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto create;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rd = td;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto writecheck;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
944e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	create:
9458b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Create the bad block table by scanning the device? */
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(td->options & NAND_BBT_CREATE))
94761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner			continue;
94861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Create the table in memory by scanning the chip(s) */
95053d5d8885089b8abeb487392311ed18f897deb93Brian Norris		if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
951453281a973c10bce941b240d1c654d536623b16bSebastian Andrzej Siewior			create_bbt(mtd, buf, bd, chipsel);
95261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td->version[i] = 1;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (md)
95561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner			md->version[i] = 1;
956e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	writecheck:
9578b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Read back first? */
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rd)
959e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			read_abs_bbt(mtd, buf, rd, chipsel);
9608b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* If they weren't versioned, read both */
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rd2)
962e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			read_abs_bbt(mtd, buf, rd2, chipsel);
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9648b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Write the bad block table to the device? */
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
966e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			res = write_bbt(mtd, buf, td, md, chipsel);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res < 0)
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
97061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
9718b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/* Write the mirror bad block table to the device? */
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
973e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			res = write_bbt(mtd, buf, md, td, chipsel);
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res < 0)
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return res;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
97861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	return 0;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
98261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * mark_bbt_regions - [GENERIC] mark the bad block table regions
9838b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
9848b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @td: bad block table descriptor
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9868b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The bad block table regions are marked as "bad" to prevent accidental
9878b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * erasures / writes. The regions are identified by the mark 0x02.
9888b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
989e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhousestatic void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, chips, block, nrblocks, update;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t oldval, newval;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9958b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = this->numchips;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chips = 1;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
100261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
100361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < chips; i++) {
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((td->options & NAND_BBT_ABSPAGE) ||
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    !(td->options & NAND_BBT_WRITE)) {
1007e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			if (td->pages[i] == -1)
1008e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse				continue;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
101061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner			block <<= 1;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oldval = this->bbt[(block >> 3)];
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			newval = oldval | (0x2 << (block & 0x06));
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt[(block >> 3)] = newval;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((oldval != newval) && td->reserved_block_code)
101569423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter				nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		update = 0;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (td->options & NAND_BBT_LASTBLOCK)
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block = ((i + 1) * nrblocks) - td->maxblocks;
102161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		else
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block = i * nrblocks;
102361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		block <<= 1;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < td->maxblocks; j++) {
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			oldval = this->bbt[(block >> 3)];
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			newval = oldval | (0x2 << (block & 0x06));
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt[(block >> 3)] = newval;
1028e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			if (oldval != newval)
1029e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse				update = 1;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			block += 2;
103161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
10328b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		/*
10338b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * If we want reserved blocks to be recorded to flash, and some
10348b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * new ones have been marked, then we need to update the stored
10358b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 * bbts.  This should only happen once.
10368b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris		 */
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (update && td->reserved_block_code)
103869423d99fc182a81f3c5db3eb5c140acc6fc64beAdrian Hunter			nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
10437cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * verify_bbt_descr - verify the bad block description
10448b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
10458b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: the table to verify
10467cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior *
10477cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * This functions performs a few sanity checks on the bad block description
10487cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior * table.
10497cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior */
10507cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
10517cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior{
10527cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	struct nand_chip *this = mtd->priv;
10537912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	u32 pattern_len;
10547912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	u32 bits;
10557cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	u32 table_size;
10567cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10577cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (!bd)
10587cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		return;
10597912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev
10607912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	pattern_len = bd->len;
10617912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev	bits = bd->options & NAND_BBT_NRBITS_MSK;
10627912a5e7f37512d8d105785046137435b70347ceStanislav Fomichev
1063a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
1064bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris			!(this->bbt_options & NAND_BBT_USE_FLASH));
10657cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	BUG_ON(!bits);
10667cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10677cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_VERSION)
10687cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		pattern_len++;
10697cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10707cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_NO_OOB) {
1071bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
1072a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
10737cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		BUG_ON(bd->offs);
10747cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		if (bd->options & NAND_BBT_VERSION)
10757cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			BUG_ON(bd->veroffs != bd->len);
10767cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
10777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	}
10787cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10797cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_PERCHIP)
10807cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		table_size = this->chipsize >> this->bbt_erase_shift;
10817cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	else
10827cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		table_size = mtd->size >> this->bbt_erase_shift;
10837cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	table_size >>= 3;
10847cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	table_size *= bits;
10857cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	if (bd->options & NAND_BBT_NO_OOB)
10867cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		table_size += pattern_len;
10877cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	BUG_ON(table_size > (1 << this->bbt_erase_shift));
10887cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior}
10897cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
10907cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior/**
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
10928b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
10938b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @bd: descriptor for the good/bad block search pattern
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10958b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function checks, if a bad block table(s) is/are already available. If
10968b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * not it scans the device for manufacturer marked good / bad blocks and writes
10978b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the bad block table(s) to the selected place.
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10998b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The bad block table memory is allocated here. It must be freed by calling
11008b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * the nand_free_bbt function.
11018b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1102e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len, res = 0;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *buf;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *td = this->bbt_td;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *md = this->bbt_md;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = mtd->size >> (this->bbt_erase_shift + 2);
11118b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/*
11128b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * Allocate memory (2bit per block) and clear the memory bad block
11138b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * table.
11148b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 */
111595b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan	this->bbt = kzalloc(len, GFP_KERNEL);
11160870066d7e6c85bbe37741137e4c4731501a98e0Brian Norris	if (!this->bbt)
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11198b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/*
11208b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * If no primary table decriptor is given, scan the device to build a
11218b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * memory based bad block table.
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1123eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	if (!td) {
1124eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		if ((res = nand_memory_bbt(mtd, bd))) {
1125d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
1126e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse			kfree(this->bbt);
1127eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy			this->bbt = NULL;
1128eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		}
1129eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy		return res;
1130eeada24da8bd23fcf6acd2729be054ea99b301bbArtem B. Bityuckiy	}
11317cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	verify_bbt_descr(mtd, td);
11327cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	verify_bbt_descr(mtd, md);
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allocate a temporary buffer for one eraseblock incl. oob */
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (1 << this->bbt_erase_shift);
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += (len >> this->page_shift) * mtd->oobsize;
1137c3f8abf481c2d2b221b028f7369bc6dd39a9590eDavid Woodhouse	buf = vmalloc(len);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf) {
1139e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		kfree(this->bbt);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		this->bbt = NULL;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
114361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
11448b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Is the bbt at a given page? */
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_ABSPAGE) {
1146e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = read_abs_bbts(mtd, buf, td, md);
114761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	} else {
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Search the bad block table using a pattern in oob */
1149e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = search_read_bbts(mtd, buf, td, md);
115061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	}
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
115261b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	if (res)
1153e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = check_create(mtd, buf, bd);
115461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Prevent the bbt regions from erasing / writing */
1156e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	mark_bbt_region(mtd, td);
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md)
1158e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		mark_bbt_region(mtd, md);
115961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
1160e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	vfree(buf);
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
116561b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * nand_update_bbt - [NAND Interface] update bad block table(s)
11668b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
11678b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @offs: the offset of the newly marked block
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11698b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * The function updates the bad block table(s).
11708b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1171e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_update_bbt(struct mtd_info *mtd, loff_t offs)
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len, res = 0, writeops = 0;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chip, chipsel;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint8_t *buf;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *td = this->bbt_td;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_bbt_descr *md = this->bbt_md;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!this->bbt || !td)
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allocate a temporary buffer for one eraseblock incl. oob */
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (1 << this->bbt_erase_shift);
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += (len >> this->page_shift) * mtd->oobsize;
1186e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	buf = kmalloc(len, GFP_KERNEL);
11870870066d7e6c85bbe37741137e4c4731501a98e0Brian Norris	if (!buf)
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
118961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeops = md != NULL ? 0x03 : 0x01;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11928b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Do we have a bbt per chip? */
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->options & NAND_BBT_PERCHIP) {
1194e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		chip = (int)(offs >> this->chip_shift);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chipsel = chip;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip = 0;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chipsel = -1;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	td->version[chip]++;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (md)
120361b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		md->version[chip]++;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12058b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Write the bad block table to the device? */
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
1207e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = write_bbt(mtd, buf, td, md, chipsel);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res < 0)
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12118b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Write the mirror bad block table to the device? */
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
1213e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		res = write_bbt(mtd, buf, md, td, chipsel);
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1216e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse out:
1217e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	kfree(buf);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12218b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris/*
12228b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * Define some generic bad / good block scan pattern which are used
12238b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * while scanning a device for factory marked good / bad blocks.
12248b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t scan_ff_pattern[] = { 0xff, 0xff };
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_bbt_descr agand_flashbased = {
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.offs = 0x20,
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.len = 6,
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pattern = scan_agand_pattern
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12367854d3f7495b11be1570cd3e2318674d8f9ed797Brian Norris/* Generic flash bbt descriptors */
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_bbt_descr bbt_main_descr = {
124161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.offs =	8,
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.len = 4,
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.veroffs = 12,
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.maxblocks = 4,
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pattern = bbt_pattern
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_bbt_descr bbt_mirror_descr = {
125161b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.offs =	8,
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.len = 4,
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.veroffs = 12,
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.maxblocks = 4,
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pattern = mirror_pattern
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12607cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic struct nand_bbt_descr bbt_main_no_bbt_descr = {
12617cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12627cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
12637cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_NO_OOB,
12647cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.len = 4,
12657cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.veroffs = 4,
12667cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.maxblocks = 4,
12677cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.pattern = bbt_pattern
12687cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior};
12697cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
12707cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewiorstatic struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
12717cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12727cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
12737cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior		| NAND_BBT_NO_OOB,
12747cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.len = 4,
12757cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.veroffs = 4,
12767cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.maxblocks = 4,
12777cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior	.pattern = mirror_pattern
12787cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior};
12797cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior
128058373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris/**
12817854d3f7495b11be1570cd3e2318674d8f9ed797Brian Norris * nand_create_default_bbt_descr - [INTERN] Creates a BBT descriptor structure
12828b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @this: NAND chip to create descriptor for
128358373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris *
128458373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris * This function allocates and initializes a nand_bbt_descr for BBM detection
128558373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris * based on the properties of "this". The new descriptor is stored in
128658373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
128758373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris * passed to this function.
128858373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris */
128958373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norrisstatic int nand_create_default_bbt_descr(struct nand_chip *this)
129058373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris{
129158373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	struct nand_bbt_descr *bd;
129258373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	if (this->badblock_pattern) {
1293d037021953922ebdbc34b98b8c4648017b1c6e89Brian Norris		pr_warn("BBT descr already allocated; not replacing\n");
129458373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		return -EINVAL;
129558373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	}
129658373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
12970870066d7e6c85bbe37741137e4c4731501a98e0Brian Norris	if (!bd)
129858373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris		return -ENOMEM;
12995fb1549dfc40f3b589dae560ea21535cdc5f64e0Brian Norris	bd->options = this->bbt_options;
130058373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->offs = this->badblockpos;
130158373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
130258373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->pattern = scan_ff_pattern;
130358373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	bd->options |= NAND_BBT_DYNAMICSTRUCT;
130458373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	this->badblock_pattern = bd;
130558373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris	return 0;
130658373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris}
130758373ff0afff4cc8ac40608872995f4d87eb72ecBrian Norris
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
130961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
13108b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
13128b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * This function selects the default bad block table support for the device and
13138b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * calls the nand_scan_bbt function.
13148b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1315e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_default_bbt(struct mtd_info *mtd)
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
131861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
13198b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/*
13208b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * Default for AG-AND. We must use a flash based bad block table as the
13218b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * devices have factory marked _good_ blocks. Erasing those blocks
13228b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * leads to loss of the good / bad information, so we _must_ store this
13238b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	 * information in a good / bad table during startup.
1324e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	 */
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (this->options & NAND_IS_AND) {
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Use the default pattern descriptors */
132761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		if (!this->bbt_td) {
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt_td = &bbt_main_descr;
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this->bbt_md = &bbt_mirror_descr;
133061b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		}
1331bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris		this->bbt_options |= NAND_BBT_USE_FLASH;
1332e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return nand_scan_bbt(mtd, &agand_flashbased);
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
133461b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
13358b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris	/* Is a flash based bad block table requested? */
1336bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris	if (this->bbt_options & NAND_BBT_USE_FLASH) {
133761b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		/* Use the default pattern descriptors */
133861b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner		if (!this->bbt_td) {
1339a40f73419f02e40555f692785ea1c1813d5b4c12Brian Norris			if (this->bbt_options & NAND_BBT_NO_OOB) {
13407cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_td = &bbt_main_no_bbt_descr;
13417cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_md = &bbt_mirror_no_bbt_descr;
13427cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			} else {
13437cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_td = &bbt_main_descr;
13447cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior				this->bbt_md = &bbt_mirror_descr;
13457cba7b14fe179969d7217cca52e28519d7d6ca89Sebastian Andrzej Siewior			}
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		this->bbt_td = NULL;
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		this->bbt_md = NULL;
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1351a2f812df0b3d467db2ae5e3be38c36ff692ff99fBrian Norris
1352a2f812df0b3d467db2ae5e3be38c36ff692ff99fBrian Norris	if (!this->badblock_pattern)
1353a2f812df0b3d467db2ae5e3be38c36ff692ff99fBrian Norris		nand_create_default_bbt_descr(this);
1354a2f812df0b3d467db2ae5e3be38c36ff692ff99fBrian Norris
1355e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	return nand_scan_bbt(mtd, this->badblock_pattern);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
135961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner * nand_isbad_bbt - [NAND Interface] Check if a block is bad
13608b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @mtd: MTD device structure
13618b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @offs: offset in the device
13628b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris * @allowbbt: allow access to bad block table region
13638b6e50c9eba8bf44b2dfd931d359706a461d2cfdBrian Norris */
1364e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouseint nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_chip *this = mtd->priv;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int block;
1368e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	uint8_t res;
136961b03bd7c3b55498c6180d43bf71b7bf49114b64Thomas Gleixner
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get block number * 2 */
1371e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	block = (int)(offs >> (this->bbt_erase_shift - 1));
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1374289c05222172b51401dbbb017115655f241d94abBrian Norris	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
1375289c05222172b51401dbbb017115655f241d94abBrian Norris			"(block %d) 0x%02x\n",
1376289c05222172b51401dbbb017115655f241d94abBrian Norris			(unsigned int)offs, block >> 1, res);
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch ((int)res) {
1379e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	case 0x00:
1380e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return 0;
1381e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	case 0x01:
1382e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return 1;
1383e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse	case 0x02:
1384e0c7d7675331140e5186d2d1a0efce1d3877d379David Woodhouse		return allowbbt ? 0 : 1;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1389e0c7d7675331140e5186d2d1a0efce1d3877d379David WoodhouseEXPORT_SYMBOL(nand_scan_bbt);
1390e0c7d7675331140e5186d2d1a0efce1d3877d379David WoodhouseEXPORT_SYMBOL(nand_default_bbt);
1391