blob: 3df8d92c5e08507ae5d3321bdf57605ada8d9b0c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/mtd/nand_bbt.c
3 *
4 * Overview:
5 * Bad block table support for the NAND driver
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00006 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Description:
14 *
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000015 * When nand_scan_bbt is called, then it tries to find the bad block table
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020016 * depending on the options in the BBT descriptor(s). If no flash based BBT
Brian Norrisbb9ebd42011-05-31 16:31:23 -070017 * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020018 * marked good / bad blocks. This information is used to create a memory BBT.
19 * Once a new bad block is discovered then the "factory" information is updated
20 * on the device.
21 * If a flash based BBT is specified then the function first tries to find the
22 * BBT on flash. If a BBT is found then the contents are read and the memory
23 * based BBT is created. If a mirrored BBT is selected then the mirror is
24 * searched too and the versions are compared. If the mirror has a greater
25 * version number than the mirror BBT is used to build the memory based BBT.
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 * If the tables are not versioned, then we "or" the bad block information.
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020027 * If one of the BBTs is out of date or does not exist it is (re)created.
28 * If no BBT exists at all then the device is scanned for factory marked
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000029 * good / bad blocks and the bad block tables are created.
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 *
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020031 * For manufacturer created BBTs like the one found on M-SYS DOC devices
32 * the BBT is searched and read but never created
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 *
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020034 * The auto generated bad block table is located in the last good blocks
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000035 * of the device. The table is mirrored, so it can be updated eventually.
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020036 * The table is marked in the OOB area with an ident pattern and a version
37 * number which indicates which of both tables is more up to date. If the NAND
38 * controller needs the complete OOB area for the ECC information then the
Brian Norrisbb9ebd42011-05-31 16:31:23 -070039 * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
Brian Norrisa40f7342011-05-31 16:31:22 -070040 * course): it moves the ident pattern and the version byte into the data area
41 * and the OOB area will remain untouched.
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 *
43 * The table uses 2 bits per block
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020044 * 11b: block is good
45 * 00b: block is factory marked bad
46 * 01b, 10b: block is marked bad due to wear
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 *
48 * The memory bad block table uses the following scheme:
49 * 00b: block is good
50 * 01b: block is marked bad due to wear
51 * 10b: block is reserved (to protect the bbt area)
52 * 11b: block is factory marked bad
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000053 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 * Multichip devices like DOC store the bad block info per floor.
55 *
56 * Following assumptions are made:
57 * - bbts start at a page boundary, if autolocated on a block boundary
David Woodhousee0c7d762006-05-13 18:07:53 +010058 * - the space necessary for a bbt in FLASH does not exceed a block boundary
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000059 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 */
61
62#include <linux/slab.h>
63#include <linux/types.h>
64#include <linux/mtd/mtd.h>
65#include <linux/mtd/nand.h>
66#include <linux/mtd/nand_ecc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <linux/bitops.h>
68#include <linux/delay.h>
David Woodhousec3f8abf2006-05-13 04:03:42 +010069#include <linux/vmalloc.h>
Paul Gortmakerf3bcc012011-07-10 12:43:28 -040070#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020072static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
73{
Brian Norris718894a2012-06-22 16:35:43 -070074 if (memcmp(buf, td->pattern, td->len))
75 return -1;
76 return 0;
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020077}
78
Thomas Gleixner61b03bd2005-11-07 11:15:49 +000079/**
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 * check_pattern - [GENERIC] check if a pattern is in the buffer
Brian Norris8b6e50c2011-05-25 14:59:01 -070081 * @buf: the buffer to search
82 * @len: the length of buffer to search
83 * @paglen: the pagelength
84 * @td: search pattern descriptor
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 *
Brian Norris8b6e50c2011-05-25 14:59:01 -070086 * Check for a pattern at the given place. Used to search bad block tables and
87 * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
88 * all bytes except the pattern area contain 0xff.
89 */
David Woodhousee0c7d762006-05-13 18:07:53 +010090static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091{
Artem B. Bityuckiy171650a2005-02-16 17:09:39 +000092 int i, end = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 uint8_t *p = buf;
94
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +020095 if (td->options & NAND_BBT_NO_OOB)
96 return check_pattern_no_oob(buf, td);
97
Thomas Gleixnerc9e053652005-06-14 16:39:57 +010098 end = paglen + td->offs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 if (td->options & NAND_BBT_SCANEMPTY) {
100 for (i = 0; i < end; i++) {
101 if (p[i] != 0xff)
102 return -1;
103 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000104 }
Thomas Gleixnerc9e053652005-06-14 16:39:57 +0100105 p += end;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 /* Compare the pattern */
Brian Norris75b66d82011-09-07 13:13:41 -0700108 if (memcmp(p, td->pattern, td->len))
109 return -1;
Brian Norris58373ff2010-07-15 12:15:44 -0700110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 if (td->options & NAND_BBT_SCANEMPTY) {
Artem B. Bityuckiy171650a2005-02-16 17:09:39 +0000112 p += td->len;
113 end += td->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 for (i = end; i < len; i++) {
115 if (*p++ != 0xff)
116 return -1;
117 }
118 }
119 return 0;
120}
121
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000122/**
Thomas Gleixnerc9e053652005-06-14 16:39:57 +0100123 * check_short_pattern - [GENERIC] check if a pattern is in the buffer
Brian Norris8b6e50c2011-05-25 14:59:01 -0700124 * @buf: the buffer to search
125 * @td: search pattern descriptor
Thomas Gleixnerc9e053652005-06-14 16:39:57 +0100126 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700127 * Check for a pattern at the given place. Used to search bad block tables and
128 * good / bad block identifiers. Same as check_pattern, but no optional empty
129 * check.
130 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100131static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
Thomas Gleixnerc9e053652005-06-14 16:39:57 +0100132{
133 int i;
134 uint8_t *p = buf;
135
136 /* Compare the pattern */
137 for (i = 0; i < td->len; i++) {
Thomas Gleixner19870da2005-07-15 14:53:51 +0100138 if (p[td->offs + i] != td->pattern[i])
Thomas Gleixnerc9e053652005-06-14 16:39:57 +0100139 return -1;
140 }
141 return 0;
142}
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144/**
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200145 * add_marker_len - compute the length of the marker in data area
Brian Norris8b6e50c2011-05-25 14:59:01 -0700146 * @td: BBT descriptor used for computation
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200147 *
Brian Norris7854d3f2011-06-23 14:12:08 -0700148 * The length will be 0 if the marker is located in OOB area.
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200149 */
150static u32 add_marker_len(struct nand_bbt_descr *td)
151{
152 u32 len;
153
154 if (!(td->options & NAND_BBT_NO_OOB))
155 return 0;
156
157 len = td->len;
158 if (td->options & NAND_BBT_VERSION)
159 len++;
160 return len;
161}
162
163/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 * read_bbt - [GENERIC] Read the bad block table starting from page
Brian Norris8b6e50c2011-05-25 14:59:01 -0700165 * @mtd: MTD device structure
166 * @buf: temporary buffer
167 * @page: the starting page
168 * @num: the number of bbt descriptors to read
Brian Norris7854d3f2011-06-23 14:12:08 -0700169 * @td: the bbt describtion table
Brian Norris8b6e50c2011-05-25 14:59:01 -0700170 * @offs: offset in the memory table
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 *
172 * Read the bad block table starting from page.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100174static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
Sebastian Andrzej Siewiordf5b4e32010-09-29 19:43:51 +0200175 struct nand_bbt_descr *td, int offs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
Brian Norris167a8d52011-09-20 18:35:08 -0700177 int res, ret = 0, i, j, act = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 struct nand_chip *this = mtd->priv;
179 size_t retlen, len, totlen;
180 loff_t from;
Sebastian Andrzej Siewiordf5b4e32010-09-29 19:43:51 +0200181 int bits = td->options & NAND_BBT_NRBITS_MSK;
Brian Norris596d7452011-09-07 13:13:33 -0700182 uint8_t msk = (uint8_t)((1 << bits) - 1);
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200183 u32 marker_len;
Sebastian Andrzej Siewiordf5b4e32010-09-29 19:43:51 +0200184 int reserved_block_code = td->reserved_block_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 totlen = (num * bits) >> 3;
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200187 marker_len = add_marker_len(td);
Brian Norris596d7452011-09-07 13:13:33 -0700188 from = ((loff_t)page) << this->page_shift;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 while (totlen) {
Brian Norris596d7452011-09-07 13:13:33 -0700191 len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200192 if (marker_len) {
193 /*
194 * In case the BBT marker is not in the OOB area it
195 * will be just in the first page.
196 */
197 len -= marker_len;
198 from += marker_len;
199 marker_len = 0;
200 }
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200201 res = mtd_read(mtd, from, len, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 if (res < 0) {
Brian Norris167a8d52011-09-20 18:35:08 -0700203 if (mtd_is_eccerr(res)) {
204 pr_info("nand_bbt: ECC error in BBT at "
205 "0x%012llx\n", from & ~mtd->writesize);
206 return res;
207 } else if (mtd_is_bitflip(res)) {
208 pr_info("nand_bbt: corrected error in BBT at "
209 "0x%012llx\n", from & ~mtd->writesize);
210 ret = res;
211 } else {
212 pr_info("nand_bbt: error reading BBT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 return res;
214 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 /* Analyse data */
218 for (i = 0; i < len; i++) {
219 uint8_t dat = buf[i];
220 for (j = 0; j < 8; j += bits, act += 2) {
221 uint8_t tmp = (dat >> j) & msk;
222 if (tmp == msk)
223 continue;
David Woodhousee0c7d762006-05-13 18:07:53 +0100224 if (reserved_block_code && (tmp == reserved_block_code)) {
Brian Norrisd0370212011-07-19 10:06:08 -0700225 pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
226 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
Thomas Gleixnerf1a28c02006-05-30 00:37:34 +0200228 mtd->ecc_stats.bbtblocks++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 continue;
230 }
Brian Norris8b6e50c2011-05-25 14:59:01 -0700231 /*
232 * Leave it for now, if it's matured we can
Brian Norrisa0f50802011-07-19 10:06:06 -0700233 * move this message to pr_debug.
Brian Norris8b6e50c2011-05-25 14:59:01 -0700234 */
Brian Norrisd0370212011-07-19 10:06:08 -0700235 pr_info("nand_read_bbt: bad block at 0x%012llx\n",
236 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
Brian Norris8b6e50c2011-05-25 14:59:01 -0700237 /* Factory marked bad or worn out? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 if (tmp == 0)
239 this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
240 else
241 this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
Thomas Gleixnerf1a28c02006-05-30 00:37:34 +0200242 mtd->ecc_stats.badblocks++;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 }
245 totlen -= len;
246 from += len;
247 }
Brian Norris167a8d52011-09-20 18:35:08 -0700248 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249}
250
251/**
252 * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
Brian Norris8b6e50c2011-05-25 14:59:01 -0700253 * @mtd: MTD device structure
254 * @buf: temporary buffer
255 * @td: descriptor for the bad block table
Brian Norris596d7452011-09-07 13:13:33 -0700256 * @chip: read the table for a specific chip, -1 read all chips; applies only if
Brian Norris8b6e50c2011-05-25 14:59:01 -0700257 * NAND_BBT_PERCHIP option is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700259 * Read the bad block table for all chips starting at a given page. We assume
260 * that the bbt bits are in consecutive order.
261 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100262static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
264 struct nand_chip *this = mtd->priv;
265 int res = 0, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 if (td->options & NAND_BBT_PERCHIP) {
268 int offs = 0;
269 for (i = 0; i < this->numchips; i++) {
270 if (chip == -1 || chip == i)
Sebastian Andrzej Siewiordf5b4e32010-09-29 19:43:51 +0200271 res = read_bbt(mtd, buf, td->pages[i],
272 this->chipsize >> this->bbt_erase_shift,
273 td, offs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 if (res)
275 return res;
276 offs += this->chipsize >> (this->bbt_erase_shift + 2);
277 }
278 } else {
Sebastian Andrzej Siewiordf5b4e32010-09-29 19:43:51 +0200279 res = read_bbt(mtd, buf, td->pages[0],
280 mtd->size >> this->bbt_erase_shift, td, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 if (res)
282 return res;
283 }
284 return 0;
285}
286
Brian Norris8b6e50c2011-05-25 14:59:01 -0700287/* BBT marker is in the first page, no OOB */
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200288static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
289 struct nand_bbt_descr *td)
290{
291 size_t retlen;
292 size_t len;
293
294 len = td->len;
295 if (td->options & NAND_BBT_VERSION)
296 len++;
297
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200298 return mtd_read(mtd, offs, len, &retlen, buf);
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200299}
300
Brian Norris8b6e50c2011-05-25 14:59:01 -0700301/* Scan read raw data from flash */
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200302static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200303 size_t len)
304{
305 struct mtd_oob_ops ops;
Maxim Levitskyb64d39d2010-02-22 20:39:37 +0200306 int res;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200307
Brian Norris0612b9d2011-08-30 18:45:40 -0700308 ops.mode = MTD_OPS_RAW;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200309 ops.ooboffs = 0;
310 ops.ooblen = mtd->oobsize;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200311
Maxim Levitskyb64d39d2010-02-22 20:39:37 +0200312 while (len > 0) {
Brian Norris105513c2011-09-07 13:13:28 -0700313 ops.datbuf = buf;
314 ops.len = min(len, (size_t)mtd->writesize);
315 ops.oobbuf = buf + ops.len;
Maxim Levitskyb64d39d2010-02-22 20:39:37 +0200316
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200317 res = mtd_read_oob(mtd, offs, &ops);
Maxim Levitskyb64d39d2010-02-22 20:39:37 +0200318
Brian Norrisafa17de2011-09-07 13:13:29 -0700319 if (res)
Brian Norris105513c2011-09-07 13:13:28 -0700320 return res;
Maxim Levitskyb64d39d2010-02-22 20:39:37 +0200321
322 buf += mtd->oobsize + mtd->writesize;
323 len -= mtd->writesize;
Dmitry Maluka34a57042012-05-11 20:51:51 +0300324 offs += mtd->writesize;
Maxim Levitskyb64d39d2010-02-22 20:39:37 +0200325 }
326 return 0;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200327}
328
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200329static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
330 size_t len, struct nand_bbt_descr *td)
331{
332 if (td->options & NAND_BBT_NO_OOB)
333 return scan_read_raw_data(mtd, buf, offs, td);
334 else
335 return scan_read_raw_oob(mtd, buf, offs, len);
336}
337
Brian Norris8b6e50c2011-05-25 14:59:01 -0700338/* Scan write data with oob to flash */
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200339static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
340 uint8_t *buf, uint8_t *oob)
341{
342 struct mtd_oob_ops ops;
343
Brian Norris0612b9d2011-08-30 18:45:40 -0700344 ops.mode = MTD_OPS_PLACE_OOB;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200345 ops.ooboffs = 0;
346 ops.ooblen = mtd->oobsize;
347 ops.datbuf = buf;
348 ops.oobbuf = oob;
349 ops.len = len;
350
Artem Bityutskiya2cc5ba2011-12-23 18:29:55 +0200351 return mtd_write_oob(mtd, offs, &ops);
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200352}
353
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200354static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
355{
356 u32 ver_offs = td->veroffs;
357
358 if (!(td->options & NAND_BBT_NO_OOB))
359 ver_offs += mtd->writesize;
360 return ver_offs;
361}
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363/**
364 * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
Brian Norris8b6e50c2011-05-25 14:59:01 -0700365 * @mtd: MTD device structure
366 * @buf: temporary buffer
367 * @td: descriptor for the bad block table
368 * @md: descriptor for the bad block table mirror
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700370 * Read the bad block table(s) for all chips starting at a given page. We
371 * assume that the bbt bits are in consecutive order.
372 */
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200373static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
374 struct nand_bbt_descr *td, struct nand_bbt_descr *md)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 struct nand_chip *this = mtd->priv;
377
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000378 /* Read the primary version, if available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (td->options & NAND_BBT_VERSION) {
Adrian Hunter69423d92008-12-10 13:37:21 +0000380 scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200381 mtd->writesize, td);
382 td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
Brian Norris9a4d4d62011-07-19 10:06:07 -0700383 pr_info("Bad block table at page %d, version 0x%02X\n",
Brian Norrisd0370212011-07-19 10:06:08 -0700384 td->pages[0], td->version[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000387 /* Read the mirror version, if available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (md && (md->options & NAND_BBT_VERSION)) {
Adrian Hunter69423d92008-12-10 13:37:21 +0000389 scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
Shmulik Ladkani7bb9c752012-06-10 13:58:12 +0300390 mtd->writesize, md);
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200391 md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
Brian Norris9a4d4d62011-07-19 10:06:07 -0700392 pr_info("Bad block table at page %d, version 0x%02X\n",
Brian Norrisd0370212011-07-19 10:06:08 -0700393 md->pages[0], md->version[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return 1;
396}
397
Brian Norris8b6e50c2011-05-25 14:59:01 -0700398/* Scan a given block full */
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200399static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
400 loff_t offs, uint8_t *buf, size_t readlen,
401 int scanlen, int len)
402{
403 int ret, j;
404
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200405 ret = scan_read_raw_oob(mtd, buf, offs, readlen);
Brian Norrisafa17de2011-09-07 13:13:29 -0700406 /* Ignore ECC errors when checking for BBM */
Brian Norrisd57f40542011-09-20 18:34:25 -0700407 if (ret && !mtd_is_bitflip_or_eccerr(ret))
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200408 return ret;
409
410 for (j = 0; j < len; j++, buf += scanlen) {
411 if (check_pattern(buf, scanlen, mtd->writesize, bd))
412 return 1;
413 }
414 return 0;
415}
416
Brian Norris8b6e50c2011-05-25 14:59:01 -0700417/* Scan a given block partially */
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200418static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
419 loff_t offs, uint8_t *buf, int len)
420{
421 struct mtd_oob_ops ops;
422 int j, ret;
423
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200424 ops.ooblen = mtd->oobsize;
425 ops.oobbuf = buf;
426 ops.ooboffs = 0;
427 ops.datbuf = NULL;
Brian Norris0612b9d2011-08-30 18:45:40 -0700428 ops.mode = MTD_OPS_PLACE_OOB;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200429
430 for (j = 0; j < len; j++) {
431 /*
Brian Norris8b6e50c2011-05-25 14:59:01 -0700432 * Read the full oob until read_oob is fixed to handle single
433 * byte reads for 16 bit buswidth.
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200434 */
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200435 ret = mtd_read_oob(mtd, offs, &ops);
Brian Norris903cd062011-06-28 16:28:58 -0700436 /* Ignore ECC errors when checking for BBM */
Brian Norrisd57f40542011-09-20 18:34:25 -0700437 if (ret && !mtd_is_bitflip_or_eccerr(ret))
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200438 return ret;
439
440 if (check_short_pattern(buf, bd))
441 return 1;
442
443 offs += mtd->writesize;
444 }
445 return 0;
446}
447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448/**
449 * create_bbt - [GENERIC] Create a bad block table by scanning the device
Brian Norris8b6e50c2011-05-25 14:59:01 -0700450 * @mtd: MTD device structure
451 * @buf: temporary buffer
452 * @bd: descriptor for the good/bad block search pattern
453 * @chip: create the table for a specific chip, -1 read all chips; applies only
454 * if NAND_BBT_PERCHIP option is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700456 * Create a bad block table by scanning the device for the given good/bad block
457 * identify pattern.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 */
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200459static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
460 struct nand_bbt_descr *bd, int chip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 struct nand_chip *this = mtd->priv;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200463 int i, numblocks, len, scanlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 int startblock;
465 loff_t from;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200466 size_t readlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Brian Norris9a4d4d62011-07-19 10:06:07 -0700468 pr_info("Scanning device for bad blocks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 if (bd->options & NAND_BBT_SCANALLPAGES)
471 len = 1 << (this->bbt_erase_shift - this->page_shift);
Brian Norris58373ff2010-07-15 12:15:44 -0700472 else if (bd->options & NAND_BBT_SCAN2NDPAGE)
473 len = 2;
474 else
475 len = 1;
Artem B. Bityuckiy171650a2005-02-16 17:09:39 +0000476
477 if (!(bd->options & NAND_BBT_SCANEMPTY)) {
478 /* We need only read few bytes from the OOB area */
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200479 scanlen = 0;
Artem B. Bityuckiyeeada242005-02-11 10:14:15 +0000480 readlen = bd->len;
481 } else {
Artem B. Bityuckiy171650a2005-02-16 17:09:39 +0000482 /* Full page content should be read */
Joern Engel28318772006-05-22 23:18:05 +0200483 scanlen = mtd->writesize + mtd->oobsize;
484 readlen = len * mtd->writesize;
Artem B. Bityuckiyeeada242005-02-11 10:14:15 +0000485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487 if (chip == -1) {
Brian Norris8b6e50c2011-05-25 14:59:01 -0700488 /*
489 * Note that numblocks is 2 * (real numblocks) here, see i+=2
490 * below as it makes shifting and masking less painful
491 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 numblocks = mtd->size >> (this->bbt_erase_shift - 1);
493 startblock = 0;
494 from = 0;
495 } else {
496 if (chip >= this->numchips) {
Brian Norris9a4d4d62011-07-19 10:06:07 -0700497 pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
David Woodhousee0c7d762006-05-13 18:07:53 +0100498 chip + 1, this->numchips);
Artem B. Bityuckiy171650a2005-02-16 17:09:39 +0000499 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501 numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
502 startblock = chip * numblocks;
503 numblocks += startblock;
Adrian Hunter69423d92008-12-10 13:37:21 +0000504 from = (loff_t)startblock << (this->bbt_erase_shift - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000506
Brian Norris5fb15492011-05-31 16:31:21 -0700507 if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
Kevin Cernekeeb60b08b2010-05-04 20:58:10 -0700508 from += mtd->erasesize - (mtd->writesize * len);
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 for (i = startblock; i < numblocks;) {
Artem B. Bityuckiyeeada242005-02-11 10:14:15 +0000511 int ret;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000512
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200513 BUG_ON(bd->options & NAND_BBT_NO_OOB);
514
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200515 if (bd->options & NAND_BBT_SCANALLPAGES)
516 ret = scan_block_full(mtd, bd, from, buf, readlen,
517 scanlen, len);
518 else
519 ret = scan_block_fast(mtd, bd, from, buf, len);
Artem B. Bityuckiy171650a2005-02-16 17:09:39 +0000520
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200521 if (ret < 0)
522 return ret;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000523
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200524 if (ret) {
525 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
Brian Norris9a4d4d62011-07-19 10:06:07 -0700526 pr_warn("Bad eraseblock %d at 0x%012llx\n",
Brian Norrisd0370212011-07-19 10:06:08 -0700527 i >> 1, (unsigned long long)from);
Thomas Gleixnerf1a28c02006-05-30 00:37:34 +0200528 mtd->ecc_stats.badblocks++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 i += 2;
532 from += (1 << this->bbt_erase_shift);
533 }
Artem B. Bityuckiyeeada242005-02-11 10:14:15 +0000534 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535}
536
537/**
538 * search_bbt - [GENERIC] scan the device for a specific bad block table
Brian Norris8b6e50c2011-05-25 14:59:01 -0700539 * @mtd: MTD device structure
540 * @buf: temporary buffer
541 * @td: descriptor for the bad block table
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700543 * Read the bad block table by searching for a given ident pattern. Search is
544 * preformed either from the beginning up or from the end of the device
545 * downwards. The search starts always at the start of a block. If the option
546 * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
547 * the bad block information of this chip. This is necessary to provide support
548 * for certain DOC devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700550 * The bbt ident pattern resides in the oob area of the first page in a block.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100552static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
554 struct nand_chip *this = mtd->priv;
555 int i, chips;
556 int bits, startblock, block, dir;
Joern Engel28318772006-05-22 23:18:05 +0200557 int scanlen = mtd->writesize + mtd->oobsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 int bbtblocks;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200559 int blocktopage = this->bbt_erase_shift - this->page_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
Brian Norris8b6e50c2011-05-25 14:59:01 -0700561 /* Search direction top -> down? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (td->options & NAND_BBT_LASTBLOCK) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100563 startblock = (mtd->size >> this->bbt_erase_shift) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 dir = -1;
565 } else {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000566 startblock = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 dir = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000568 }
569
Brian Norris8b6e50c2011-05-25 14:59:01 -0700570 /* Do we have a bbt per chip? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 if (td->options & NAND_BBT_PERCHIP) {
572 chips = this->numchips;
573 bbtblocks = this->chipsize >> this->bbt_erase_shift;
574 startblock &= bbtblocks - 1;
575 } else {
576 chips = 1;
577 bbtblocks = mtd->size >> this->bbt_erase_shift;
578 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 /* Number of bits for each erase block in the bbt */
581 bits = td->options & NAND_BBT_NRBITS_MSK;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 for (i = 0; i < chips; i++) {
584 /* Reset version information */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000585 td->version[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 td->pages[i] = -1;
587 /* Scan the maximum number of blocks */
588 for (block = 0; block < td->maxblocks; block++) {
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 int actblock = startblock + dir * block;
Adrian Hunter69423d92008-12-10 13:37:21 +0000591 loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 /* Read first page */
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200594 scan_read_raw(mtd, buf, offs, mtd->writesize, td);
Joern Engel28318772006-05-22 23:18:05 +0200595 if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200596 td->pages[i] = actblock << blocktopage;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 if (td->options & NAND_BBT_VERSION) {
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200598 offs = bbt_get_ver_offs(mtd, td);
599 td->version[i] = buf[offs];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 }
601 break;
602 }
603 }
604 startblock += this->chipsize >> this->bbt_erase_shift;
605 }
606 /* Check, if we found a bbt for each requested chip */
607 for (i = 0; i < chips; i++) {
608 if (td->pages[i] == -1)
Brian Norris9a4d4d62011-07-19 10:06:07 -0700609 pr_warn("Bad block table not found for chip %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 else
Brian Norrisd0370212011-07-19 10:06:08 -0700611 pr_info("Bad block table found at page %d, version "
612 "0x%02X\n", td->pages[i], td->version[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000614 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
617/**
618 * search_read_bbts - [GENERIC] scan the device for bad block table(s)
Brian Norris8b6e50c2011-05-25 14:59:01 -0700619 * @mtd: MTD device structure
620 * @buf: temporary buffer
621 * @td: descriptor for the bad block table
622 * @md: descriptor for the bad block table mirror
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700624 * Search and read the bad block table(s).
625 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100626static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 /* Search the primary table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100629 search_bbt(mtd, buf, td);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 /* Search the mirror table */
632 if (md)
David Woodhousee0c7d762006-05-13 18:07:53 +0100633 search_bbt(mtd, buf, md);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000635 /* Force result check */
636 return 1;
637}
638
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000639/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 * write_bbt - [GENERIC] (Re)write the bad block table
Brian Norris8b6e50c2011-05-25 14:59:01 -0700641 * @mtd: MTD device structure
642 * @buf: temporary buffer
643 * @td: descriptor for the bad block table
644 * @md: descriptor for the bad block table mirror
645 * @chipsel: selector for a specific chip, -1 for all
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700647 * (Re)write the bad block table.
648 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100649static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
Thomas Gleixner9223a452006-05-23 17:21:03 +0200650 struct nand_bbt_descr *td, struct nand_bbt_descr *md,
651 int chipsel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
653 struct nand_chip *this = mtd->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 struct erase_info einfo;
655 int i, j, res, chip = 0;
656 int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
Thomas Gleixner9223a452006-05-23 17:21:03 +0200657 int nrchips, bbtoffs, pageoffs, ooboffs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 uint8_t msk[4];
659 uint8_t rcode = td->reserved_block_code;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200660 size_t retlen, len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 loff_t to;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200662 struct mtd_oob_ops ops;
663
664 ops.ooblen = mtd->oobsize;
665 ops.ooboffs = 0;
666 ops.datbuf = NULL;
Brian Norris0612b9d2011-08-30 18:45:40 -0700667 ops.mode = MTD_OPS_PLACE_OOB;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669 if (!rcode)
670 rcode = 0xff;
Brian Norris8b6e50c2011-05-25 14:59:01 -0700671 /* Write bad block table per chip rather than per device? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if (td->options & NAND_BBT_PERCHIP) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100673 numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
Brian Norris8b6e50c2011-05-25 14:59:01 -0700674 /* Full device write or specific chip? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (chipsel == -1) {
676 nrchips = this->numchips;
677 } else {
678 nrchips = chipsel + 1;
679 chip = chipsel;
680 }
681 } else {
David Woodhousee0c7d762006-05-13 18:07:53 +0100682 numblocks = (int)(mtd->size >> this->bbt_erase_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 nrchips = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000684 }
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 /* Loop through the chips */
687 for (; chip < nrchips; chip++) {
Brian Norris8b6e50c2011-05-25 14:59:01 -0700688 /*
689 * There was already a version of the table, reuse the page
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000690 * This applies for absolute placement too, as we have the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 * page nr. in td->pages.
692 */
693 if (td->pages[chip] != -1) {
694 page = td->pages[chip];
695 goto write;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Brian Norris8b6e50c2011-05-25 14:59:01 -0700698 /*
699 * Automatic placement of the bad block table. Search direction
700 * top -> down?
701 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 if (td->options & NAND_BBT_LASTBLOCK) {
703 startblock = numblocks * (chip + 1) - 1;
704 dir = -1;
705 } else {
706 startblock = chip * numblocks;
707 dir = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 for (i = 0; i < td->maxblocks; i++) {
711 int block = startblock + dir * i;
712 /* Check, if the block is bad */
Thomas Gleixner9223a452006-05-23 17:21:03 +0200713 switch ((this->bbt[block >> 2] >>
714 (2 * (block & 0x03))) & 0x03) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 case 0x01:
716 case 0x03:
717 continue;
718 }
Thomas Gleixner9223a452006-05-23 17:21:03 +0200719 page = block <<
720 (this->bbt_erase_shift - this->page_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* Check, if the block is used by the mirror table */
722 if (!md || md->pages[chip] != page)
723 goto write;
724 }
Brian Norris9a4d4d62011-07-19 10:06:07 -0700725 pr_err("No space left to write bad block table\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return -ENOSPC;
David Woodhousee0c7d762006-05-13 18:07:53 +0100727 write:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 /* Set up shift count and masks for the flash table */
730 bits = td->options & NAND_BBT_NRBITS_MSK;
Thomas Gleixner9223a452006-05-23 17:21:03 +0200731 msk[2] = ~rcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 switch (bits) {
Thomas Gleixner9223a452006-05-23 17:21:03 +0200733 case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
734 msk[3] = 0x01;
735 break;
736 case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
737 msk[3] = 0x03;
738 break;
739 case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
740 msk[3] = 0x0f;
741 break;
742 case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
743 msk[3] = 0xff;
744 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 default: return -EINVAL;
746 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000747
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 bbtoffs = chip * (numblocks >> 2);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000749
Brian Norris596d7452011-09-07 13:13:33 -0700750 to = ((loff_t)page) << this->page_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Brian Norris8b6e50c2011-05-25 14:59:01 -0700752 /* Must we save the block contents? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if (td->options & NAND_BBT_SAVECONTENT) {
754 /* Make it block aligned */
Brian Norris596d7452011-09-07 13:13:33 -0700755 to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 len = 1 << this->bbt_erase_shift;
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200757 res = mtd_read(mtd, to, len, &retlen, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (res < 0) {
759 if (retlen != len) {
Brian Norrisd0370212011-07-19 10:06:08 -0700760 pr_info("nand_bbt: error reading block "
761 "for writing the bad block table\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return res;
763 }
Brian Norrisd0370212011-07-19 10:06:08 -0700764 pr_warn("nand_bbt: ECC error while reading "
765 "block for writing bad block table\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
Thomas Gleixner9223a452006-05-23 17:21:03 +0200767 /* Read oob data */
Vitaly Wool70145682006-11-03 18:20:38 +0300768 ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
Thomas Gleixner8593fbc2006-05-29 03:26:58 +0200769 ops.oobbuf = &buf[len];
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200770 res = mtd_read_oob(mtd, to + mtd->writesize, &ops);
Vitaly Wool70145682006-11-03 18:20:38 +0300771 if (res < 0 || ops.oobretlen != ops.ooblen)
Thomas Gleixner9223a452006-05-23 17:21:03 +0200772 goto outerr;
773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 /* Calc the byte offset in the buffer */
775 pageoffs = page - (int)(to >> this->page_shift);
776 offs = pageoffs << this->page_shift;
777 /* Preset the bbt area with 0xff */
Brian Norris596d7452011-09-07 13:13:33 -0700778 memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
Thomas Gleixner9223a452006-05-23 17:21:03 +0200779 ooboffs = len + (pageoffs * mtd->oobsize);
780
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200781 } else if (td->options & NAND_BBT_NO_OOB) {
782 ooboffs = 0;
783 offs = td->len;
Brian Norris8b6e50c2011-05-25 14:59:01 -0700784 /* The version byte */
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200785 if (td->options & NAND_BBT_VERSION)
786 offs++;
787 /* Calc length */
Brian Norris596d7452011-09-07 13:13:33 -0700788 len = (size_t)(numblocks >> sft);
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200789 len += offs;
Brian Norris8b6e50c2011-05-25 14:59:01 -0700790 /* Make it page aligned! */
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200791 len = ALIGN(len, mtd->writesize);
792 /* Preset the buffer with 0xff */
793 memset(buf, 0xff, len);
794 /* Pattern is located at the begin of first page */
795 memcpy(buf, td->pattern, td->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 } else {
797 /* Calc length */
Brian Norris596d7452011-09-07 13:13:33 -0700798 len = (size_t)(numblocks >> sft);
Brian Norris8b6e50c2011-05-25 14:59:01 -0700799 /* Make it page aligned! */
Sebastian Andrzej Siewiorcda32092010-09-29 19:43:50 +0200800 len = ALIGN(len, mtd->writesize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 /* Preset the buffer with 0xff */
Thomas Gleixner9223a452006-05-23 17:21:03 +0200802 memset(buf, 0xff, len +
803 (len >> this->page_shift)* mtd->oobsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 offs = 0;
Thomas Gleixner9223a452006-05-23 17:21:03 +0200805 ooboffs = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 /* Pattern is located in oob area of first page */
Thomas Gleixner9223a452006-05-23 17:21:03 +0200807 memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000809
Thomas Gleixner9223a452006-05-23 17:21:03 +0200810 if (td->options & NAND_BBT_VERSION)
811 buf[ooboffs + td->veroffs] = td->version[chip];
812
Brian Norris8b6e50c2011-05-25 14:59:01 -0700813 /* Walk through the memory table */
David Woodhousee0c7d762006-05-13 18:07:53 +0100814 for (i = 0; i < numblocks;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 uint8_t dat;
816 dat = this->bbt[bbtoffs + (i >> 2)];
David Woodhousee0c7d762006-05-13 18:07:53 +0100817 for (j = 0; j < 4; j++, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 int sftcnt = (i << (3 - sft)) & sftmsk;
Brian Norris8b6e50c2011-05-25 14:59:01 -0700819 /* Do not store the reserved bbt blocks! */
Thomas Gleixner9223a452006-05-23 17:21:03 +0200820 buf[offs + (i >> sft)] &=
821 ~(msk[dat & 0x03] << sftcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 dat >>= 2;
823 }
824 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000825
David Woodhousee0c7d762006-05-13 18:07:53 +0100826 memset(&einfo, 0, sizeof(einfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 einfo.mtd = mtd;
Adrian Hunter69423d92008-12-10 13:37:21 +0000828 einfo.addr = to;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 einfo.len = 1 << this->bbt_erase_shift;
David Woodhousee0c7d762006-05-13 18:07:53 +0100830 res = nand_erase_nand(mtd, &einfo, 1);
Thomas Gleixner9223a452006-05-23 17:21:03 +0200831 if (res < 0)
832 goto outerr;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000833
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +0200834 res = scan_write_bbt(mtd, to, len, buf,
835 td->options & NAND_BBT_NO_OOB ? NULL :
836 &buf[len]);
Thomas Gleixner9223a452006-05-23 17:21:03 +0200837 if (res < 0)
838 goto outerr;
839
Brian Norrisd0370212011-07-19 10:06:08 -0700840 pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
841 (unsigned long long)to, td->version[chip]);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 /* Mark it as used */
844 td->pages[chip] = page;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 return 0;
Thomas Gleixner9223a452006-05-23 17:21:03 +0200847
848 outerr:
Brian Norrisd0370212011-07-19 10:06:08 -0700849 pr_warn("nand_bbt: error while writing bad block table %d\n", res);
Thomas Gleixner9223a452006-05-23 17:21:03 +0200850 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851}
852
853/**
854 * nand_memory_bbt - [GENERIC] create a memory based bad block table
Brian Norris8b6e50c2011-05-25 14:59:01 -0700855 * @mtd: MTD device structure
856 * @bd: descriptor for the good/bad block search pattern
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700858 * The function creates a memory based bbt by scanning the device for
859 * manufacturer / software marked good / bad blocks.
860 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100861static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
863 struct nand_chip *this = mtd->priv;
864
Artem B. Bityuckiy171650a2005-02-16 17:09:39 +0000865 bd->options &= ~NAND_BBT_SCANEMPTY;
David Woodhouse4bf63fc2006-09-25 17:08:04 +0100866 return create_bbt(mtd, this->buffers->databuf, bd, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867}
868
869/**
David Woodhousee0c7d762006-05-13 18:07:53 +0100870 * check_create - [GENERIC] create and write bbt(s) if necessary
Brian Norris8b6e50c2011-05-25 14:59:01 -0700871 * @mtd: MTD device structure
872 * @buf: temporary buffer
873 * @bd: descriptor for the good/bad block search pattern
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 *
Brian Norris8b6e50c2011-05-25 14:59:01 -0700875 * The function checks the results of the previous call to read_bbt and creates
876 * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
877 * for the chip/device. Update is necessary if one of the tables is missing or
878 * the version nr. of one table is less than the other.
879 */
David Woodhousee0c7d762006-05-13 18:07:53 +0100880static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
Brian Norris623978d2011-09-20 18:35:34 -0700882 int i, chips, writeops, create, chipsel, res, res2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 struct nand_chip *this = mtd->priv;
884 struct nand_bbt_descr *td = this->bbt_td;
885 struct nand_bbt_descr *md = this->bbt_md;
886 struct nand_bbt_descr *rd, *rd2;
887
Brian Norris8b6e50c2011-05-25 14:59:01 -0700888 /* Do we have a bbt per chip? */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000889 if (td->options & NAND_BBT_PERCHIP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 chips = this->numchips;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000891 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 chips = 1;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 for (i = 0; i < chips; i++) {
895 writeops = 0;
Brian Norrisb61bf5b2011-09-07 13:13:35 -0700896 create = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 rd = NULL;
898 rd2 = NULL;
Brian Norris623978d2011-09-20 18:35:34 -0700899 res = res2 = 0;
Brian Norris8b6e50c2011-05-25 14:59:01 -0700900 /* Per chip or per device? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
Brian Norris8b6e50c2011-05-25 14:59:01 -0700902 /* Mirrored table available? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 if (md) {
904 if (td->pages[i] == -1 && md->pages[i] == -1) {
Brian Norrisb61bf5b2011-09-07 13:13:35 -0700905 create = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 writeops = 0x03;
Brian Norrisc5e8ef92011-09-07 13:13:34 -0700907 } else if (td->pages[i] == -1) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000908 rd = md;
Brian Norris596d7452011-09-07 13:13:33 -0700909 writeops = 0x01;
Brian Norrisc5e8ef92011-09-07 13:13:34 -0700910 } else if (md->pages[i] == -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 rd = td;
Brian Norris596d7452011-09-07 13:13:33 -0700912 writeops = 0x02;
Brian Norrisc5e8ef92011-09-07 13:13:34 -0700913 } else if (td->version[i] == md->version[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 rd = td;
915 if (!(td->options & NAND_BBT_VERSION))
916 rd2 = md;
Brian Norrisc5e8ef92011-09-07 13:13:34 -0700917 } else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 rd = td;
Brian Norris596d7452011-09-07 13:13:33 -0700919 writeops = 0x02;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 } else {
921 rd = md;
Brian Norris596d7452011-09-07 13:13:33 -0700922 writeops = 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 } else {
925 if (td->pages[i] == -1) {
Brian Norrisb61bf5b2011-09-07 13:13:35 -0700926 create = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 writeops = 0x01;
Brian Norrisb61bf5b2011-09-07 13:13:35 -0700928 } else {
929 rd = td;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000932
Brian Norrisb61bf5b2011-09-07 13:13:35 -0700933 if (create) {
934 /* Create the bad block table by scanning the device? */
935 if (!(td->options & NAND_BBT_CREATE))
936 continue;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000937
Brian Norrisb61bf5b2011-09-07 13:13:35 -0700938 /* Create the table in memory by scanning the chip(s) */
939 if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
940 create_bbt(mtd, buf, bd, chipsel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Brian Norrisb61bf5b2011-09-07 13:13:35 -0700942 td->version[i] = 1;
943 if (md)
944 md->version[i] = 1;
945 }
946
Brian Norris8b6e50c2011-05-25 14:59:01 -0700947 /* Read back first? */
Brian Norris623978d2011-09-20 18:35:34 -0700948 if (rd) {
949 res = read_abs_bbt(mtd, buf, rd, chipsel);
950 if (mtd_is_eccerr(res)) {
951 /* Mark table as invalid */
952 rd->pages[i] = -1;
Brian Norrisdadc17a2011-09-20 18:35:57 -0700953 rd->version[i] = 0;
Brian Norris623978d2011-09-20 18:35:34 -0700954 i--;
955 continue;
956 }
957 }
Brian Norris8b6e50c2011-05-25 14:59:01 -0700958 /* If they weren't versioned, read both */
Brian Norris623978d2011-09-20 18:35:34 -0700959 if (rd2) {
960 res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
961 if (mtd_is_eccerr(res2)) {
962 /* Mark table as invalid */
963 rd2->pages[i] = -1;
Brian Norrisdadc17a2011-09-20 18:35:57 -0700964 rd2->version[i] = 0;
Brian Norris623978d2011-09-20 18:35:34 -0700965 i--;
966 continue;
967 }
968 }
969
970 /* Scrub the flash table(s)? */
971 if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
972 writeops = 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Brian Norrisdadc17a2011-09-20 18:35:57 -0700974 /* Update version numbers before writing */
975 if (md) {
976 td->version[i] = max(td->version[i], md->version[i]);
977 md->version[i] = td->version[i];
978 }
979
Brian Norris8b6e50c2011-05-25 14:59:01 -0700980 /* Write the bad block table to the device? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100982 res = write_bbt(mtd, buf, td, md, chipsel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (res < 0)
984 return res;
985 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000986
Brian Norris8b6e50c2011-05-25 14:59:01 -0700987 /* Write the mirror bad block table to the device? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
David Woodhousee0c7d762006-05-13 18:07:53 +0100989 res = write_bbt(mtd, buf, md, td, chipsel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 if (res < 0)
991 return res;
992 }
993 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000994 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
997/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +0000998 * mark_bbt_regions - [GENERIC] mark the bad block table regions
Brian Norris8b6e50c2011-05-25 14:59:01 -0700999 * @mtd: MTD device structure
1000 * @td: bad block table descriptor
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 *
Brian Norris8b6e50c2011-05-25 14:59:01 -07001002 * The bad block table regions are marked as "bad" to prevent accidental
1003 * erasures / writes. The regions are identified by the mark 0x02.
1004 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001005static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
1007 struct nand_chip *this = mtd->priv;
1008 int i, j, chips, block, nrblocks, update;
1009 uint8_t oldval, newval;
1010
Brian Norris8b6e50c2011-05-25 14:59:01 -07001011 /* Do we have a bbt per chip? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (td->options & NAND_BBT_PERCHIP) {
1013 chips = this->numchips;
1014 nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
1015 } else {
1016 chips = 1;
1017 nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001018 }
1019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 for (i = 0; i < chips; i++) {
1021 if ((td->options & NAND_BBT_ABSPAGE) ||
1022 !(td->options & NAND_BBT_WRITE)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001023 if (td->pages[i] == -1)
1024 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001026 block <<= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 oldval = this->bbt[(block >> 3)];
1028 newval = oldval | (0x2 << (block & 0x06));
1029 this->bbt[(block >> 3)] = newval;
1030 if ((oldval != newval) && td->reserved_block_code)
Adrian Hunter69423d92008-12-10 13:37:21 +00001031 nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 continue;
1033 }
1034 update = 0;
1035 if (td->options & NAND_BBT_LASTBLOCK)
1036 block = ((i + 1) * nrblocks) - td->maxblocks;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001037 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 block = i * nrblocks;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001039 block <<= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 for (j = 0; j < td->maxblocks; j++) {
1041 oldval = this->bbt[(block >> 3)];
1042 newval = oldval | (0x2 << (block & 0x06));
1043 this->bbt[(block >> 3)] = newval;
David Woodhousee0c7d762006-05-13 18:07:53 +01001044 if (oldval != newval)
1045 update = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 block += 2;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001047 }
Brian Norris8b6e50c2011-05-25 14:59:01 -07001048 /*
1049 * If we want reserved blocks to be recorded to flash, and some
1050 * new ones have been marked, then we need to update the stored
1051 * bbts. This should only happen once.
1052 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (update && td->reserved_block_code)
Adrian Hunter69423d92008-12-10 13:37:21 +00001054 nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
1056}
1057
1058/**
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001059 * verify_bbt_descr - verify the bad block description
Brian Norris8b6e50c2011-05-25 14:59:01 -07001060 * @mtd: MTD device structure
1061 * @bd: the table to verify
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001062 *
1063 * This functions performs a few sanity checks on the bad block description
1064 * table.
1065 */
1066static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
1067{
1068 struct nand_chip *this = mtd->priv;
Stanislav Fomichev7912a5e2011-02-07 23:48:25 +03001069 u32 pattern_len;
1070 u32 bits;
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001071 u32 table_size;
1072
1073 if (!bd)
1074 return;
Stanislav Fomichev7912a5e2011-02-07 23:48:25 +03001075
1076 pattern_len = bd->len;
1077 bits = bd->options & NAND_BBT_NRBITS_MSK;
1078
Brian Norrisa40f7342011-05-31 16:31:22 -07001079 BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001080 !(this->bbt_options & NAND_BBT_USE_FLASH));
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001081 BUG_ON(!bits);
1082
1083 if (bd->options & NAND_BBT_VERSION)
1084 pattern_len++;
1085
1086 if (bd->options & NAND_BBT_NO_OOB) {
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001087 BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
Brian Norrisa40f7342011-05-31 16:31:22 -07001088 BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001089 BUG_ON(bd->offs);
1090 if (bd->options & NAND_BBT_VERSION)
1091 BUG_ON(bd->veroffs != bd->len);
1092 BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
1093 }
1094
1095 if (bd->options & NAND_BBT_PERCHIP)
1096 table_size = this->chipsize >> this->bbt_erase_shift;
1097 else
1098 table_size = mtd->size >> this->bbt_erase_shift;
1099 table_size >>= 3;
1100 table_size *= bits;
1101 if (bd->options & NAND_BBT_NO_OOB)
1102 table_size += pattern_len;
1103 BUG_ON(table_size > (1 << this->bbt_erase_shift));
1104}
1105
1106/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
Brian Norris8b6e50c2011-05-25 14:59:01 -07001108 * @mtd: MTD device structure
1109 * @bd: descriptor for the good/bad block search pattern
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 *
Brian Norris8b6e50c2011-05-25 14:59:01 -07001111 * The function checks, if a bad block table(s) is/are already available. If
1112 * not it scans the device for manufacturer marked good / bad blocks and writes
1113 * the bad block table(s) to the selected place.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 *
Brian Norris8b6e50c2011-05-25 14:59:01 -07001115 * The bad block table memory is allocated here. It must be freed by calling
1116 * the nand_free_bbt function.
1117 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001118int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119{
1120 struct nand_chip *this = mtd->priv;
1121 int len, res = 0;
1122 uint8_t *buf;
1123 struct nand_bbt_descr *td = this->bbt_td;
1124 struct nand_bbt_descr *md = this->bbt_md;
1125
1126 len = mtd->size >> (this->bbt_erase_shift + 2);
Brian Norris8b6e50c2011-05-25 14:59:01 -07001127 /*
1128 * Allocate memory (2bit per block) and clear the memory bad block
1129 * table.
1130 */
Burman Yan95b93a02006-11-15 21:10:29 +02001131 this->bbt = kzalloc(len, GFP_KERNEL);
Brian Norris08700662011-06-07 16:01:54 -07001132 if (!this->bbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Brian Norris8b6e50c2011-05-25 14:59:01 -07001135 /*
1136 * If no primary table decriptor is given, scan the device to build a
1137 * memory based bad block table.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 */
Artem B. Bityuckiyeeada242005-02-11 10:14:15 +00001139 if (!td) {
1140 if ((res = nand_memory_bbt(mtd, bd))) {
Brian Norrisd0370212011-07-19 10:06:08 -07001141 pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
David Woodhousee0c7d762006-05-13 18:07:53 +01001142 kfree(this->bbt);
Artem B. Bityuckiyeeada242005-02-11 10:14:15 +00001143 this->bbt = NULL;
1144 }
1145 return res;
1146 }
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001147 verify_bbt_descr(mtd, td);
1148 verify_bbt_descr(mtd, md);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
1150 /* Allocate a temporary buffer for one eraseblock incl. oob */
1151 len = (1 << this->bbt_erase_shift);
1152 len += (len >> this->page_shift) * mtd->oobsize;
David Woodhousec3f8abf2006-05-13 04:03:42 +01001153 buf = vmalloc(len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (!buf) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001155 kfree(this->bbt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 this->bbt = NULL;
1157 return -ENOMEM;
1158 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001159
Brian Norris8b6e50c2011-05-25 14:59:01 -07001160 /* Is the bbt at a given page? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (td->options & NAND_BBT_ABSPAGE) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001162 res = read_abs_bbts(mtd, buf, td, md);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001163 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 /* Search the bad block table using a pattern in oob */
David Woodhousee0c7d762006-05-13 18:07:53 +01001165 res = search_read_bbts(mtd, buf, td, md);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001168 if (res)
David Woodhousee0c7d762006-05-13 18:07:53 +01001169 res = check_create(mtd, buf, bd);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 /* Prevent the bbt regions from erasing / writing */
David Woodhousee0c7d762006-05-13 18:07:53 +01001172 mark_bbt_region(mtd, td);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 if (md)
David Woodhousee0c7d762006-05-13 18:07:53 +01001174 mark_bbt_region(mtd, md);
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001175
David Woodhousee0c7d762006-05-13 18:07:53 +01001176 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return res;
1178}
1179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001181 * nand_update_bbt - [NAND Interface] update bad block table(s)
Brian Norris8b6e50c2011-05-25 14:59:01 -07001182 * @mtd: MTD device structure
1183 * @offs: the offset of the newly marked block
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 *
Brian Norris8b6e50c2011-05-25 14:59:01 -07001185 * The function updates the bad block table(s).
1186 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001187int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
1189 struct nand_chip *this = mtd->priv;
Brian Norris1196ac52011-09-07 13:13:32 -07001190 int len, res = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 int chip, chipsel;
1192 uint8_t *buf;
1193 struct nand_bbt_descr *td = this->bbt_td;
1194 struct nand_bbt_descr *md = this->bbt_md;
1195
1196 if (!this->bbt || !td)
1197 return -EINVAL;
1198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 /* Allocate a temporary buffer for one eraseblock incl. oob */
1200 len = (1 << this->bbt_erase_shift);
1201 len += (len >> this->page_shift) * mtd->oobsize;
David Woodhousee0c7d762006-05-13 18:07:53 +01001202 buf = kmalloc(len, GFP_KERNEL);
Brian Norris08700662011-06-07 16:01:54 -07001203 if (!buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return -ENOMEM;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001205
Brian Norris8b6e50c2011-05-25 14:59:01 -07001206 /* Do we have a bbt per chip? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (td->options & NAND_BBT_PERCHIP) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001208 chip = (int)(offs >> this->chip_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 chipsel = chip;
1210 } else {
1211 chip = 0;
1212 chipsel = -1;
1213 }
1214
1215 td->version[chip]++;
1216 if (md)
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001217 md->version[chip]++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Brian Norris8b6e50c2011-05-25 14:59:01 -07001219 /* Write the bad block table to the device? */
Brian Norris1196ac52011-09-07 13:13:32 -07001220 if (td->options & NAND_BBT_WRITE) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001221 res = write_bbt(mtd, buf, td, md, chipsel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 if (res < 0)
1223 goto out;
1224 }
Brian Norris8b6e50c2011-05-25 14:59:01 -07001225 /* Write the mirror bad block table to the device? */
Brian Norris1196ac52011-09-07 13:13:32 -07001226 if (md && (md->options & NAND_BBT_WRITE)) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001227 res = write_bbt(mtd, buf, md, td, chipsel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 }
1229
David Woodhousee0c7d762006-05-13 18:07:53 +01001230 out:
1231 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 return res;
1233}
1234
Brian Norris8b6e50c2011-05-25 14:59:01 -07001235/*
1236 * Define some generic bad / good block scan pattern which are used
1237 * while scanning a device for factory marked good / bad blocks.
1238 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
1242
1243static struct nand_bbt_descr agand_flashbased = {
1244 .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
1245 .offs = 0x20,
1246 .len = 6,
1247 .pattern = scan_agand_pattern
1248};
1249
Brian Norris7854d3f2011-06-23 14:12:08 -07001250/* Generic flash bbt descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
1252static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
1253
1254static struct nand_bbt_descr bbt_main_descr = {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001255 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1257 .offs = 8,
1258 .len = 4,
1259 .veroffs = 12,
1260 .maxblocks = 4,
1261 .pattern = bbt_pattern
1262};
1263
1264static struct nand_bbt_descr bbt_mirror_descr = {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001265 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1267 .offs = 8,
1268 .len = 4,
1269 .veroffs = 12,
1270 .maxblocks = 4,
1271 .pattern = mirror_pattern
1272};
1273
Brian Norris9fd6b372012-06-22 16:35:40 -07001274static struct nand_bbt_descr bbt_main_no_oob_descr = {
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001275 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1276 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
1277 | NAND_BBT_NO_OOB,
1278 .len = 4,
1279 .veroffs = 4,
1280 .maxblocks = 4,
1281 .pattern = bbt_pattern
1282};
1283
Brian Norris9fd6b372012-06-22 16:35:40 -07001284static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001285 .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1286 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
1287 | NAND_BBT_NO_OOB,
1288 .len = 4,
1289 .veroffs = 4,
1290 .maxblocks = 4,
1291 .pattern = mirror_pattern
1292};
1293
Brian Norris752ed6c2011-09-20 18:36:42 -07001294#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
Brian Norris58373ff2010-07-15 12:15:44 -07001295/**
Brian Norris752ed6c2011-09-20 18:36:42 -07001296 * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
Brian Norris8b6e50c2011-05-25 14:59:01 -07001297 * @this: NAND chip to create descriptor for
Brian Norris58373ff2010-07-15 12:15:44 -07001298 *
1299 * This function allocates and initializes a nand_bbt_descr for BBM detection
Brian Norris752ed6c2011-09-20 18:36:42 -07001300 * based on the properties of @this. The new descriptor is stored in
Brian Norris58373ff2010-07-15 12:15:44 -07001301 * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
1302 * passed to this function.
Brian Norris58373ff2010-07-15 12:15:44 -07001303 */
Brian Norris752ed6c2011-09-20 18:36:42 -07001304static int nand_create_badblock_pattern(struct nand_chip *this)
Brian Norris58373ff2010-07-15 12:15:44 -07001305{
1306 struct nand_bbt_descr *bd;
1307 if (this->badblock_pattern) {
Brian Norris752ed6c2011-09-20 18:36:42 -07001308 pr_warn("Bad block pattern already allocated; not replacing\n");
Brian Norris58373ff2010-07-15 12:15:44 -07001309 return -EINVAL;
1310 }
1311 bd = kzalloc(sizeof(*bd), GFP_KERNEL);
Brian Norris08700662011-06-07 16:01:54 -07001312 if (!bd)
Brian Norris58373ff2010-07-15 12:15:44 -07001313 return -ENOMEM;
Brian Norris752ed6c2011-09-20 18:36:42 -07001314 bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
Brian Norris58373ff2010-07-15 12:15:44 -07001315 bd->offs = this->badblockpos;
1316 bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
1317 bd->pattern = scan_ff_pattern;
1318 bd->options |= NAND_BBT_DYNAMICSTRUCT;
1319 this->badblock_pattern = bd;
1320 return 0;
1321}
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001324 * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
Brian Norris8b6e50c2011-05-25 14:59:01 -07001325 * @mtd: MTD device structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 *
Brian Norris8b6e50c2011-05-25 14:59:01 -07001327 * This function selects the default bad block table support for the device and
1328 * calls the nand_scan_bbt function.
1329 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001330int nand_default_bbt(struct mtd_info *mtd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331{
1332 struct nand_chip *this = mtd->priv;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001333
Brian Norris8b6e50c2011-05-25 14:59:01 -07001334 /*
1335 * Default for AG-AND. We must use a flash based bad block table as the
1336 * devices have factory marked _good_ blocks. Erasing those blocks
1337 * leads to loss of the good / bad information, so we _must_ store this
1338 * information in a good / bad table during startup.
David Woodhousee0c7d762006-05-13 18:07:53 +01001339 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (this->options & NAND_IS_AND) {
1341 /* Use the default pattern descriptors */
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001342 if (!this->bbt_td) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 this->bbt_td = &bbt_main_descr;
1344 this->bbt_md = &bbt_mirror_descr;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001345 }
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001346 this->bbt_options |= NAND_BBT_USE_FLASH;
David Woodhousee0c7d762006-05-13 18:07:53 +01001347 return nand_scan_bbt(mtd, &agand_flashbased);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001349
Brian Norris8b6e50c2011-05-25 14:59:01 -07001350 /* Is a flash based bad block table requested? */
Brian Norrisbb9ebd42011-05-31 16:31:23 -07001351 if (this->bbt_options & NAND_BBT_USE_FLASH) {
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001352 /* Use the default pattern descriptors */
1353 if (!this->bbt_td) {
Brian Norrisa40f7342011-05-31 16:31:22 -07001354 if (this->bbt_options & NAND_BBT_NO_OOB) {
Brian Norris9fd6b372012-06-22 16:35:40 -07001355 this->bbt_td = &bbt_main_no_oob_descr;
1356 this->bbt_md = &bbt_mirror_no_oob_descr;
Sebastian Andrzej Siewior7cba7b12010-09-30 21:28:01 +02001357 } else {
1358 this->bbt_td = &bbt_main_descr;
1359 this->bbt_md = &bbt_mirror_descr;
1360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 } else {
1363 this->bbt_td = NULL;
1364 this->bbt_md = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 }
Brian Norrisa2f812d2011-03-18 21:53:42 -07001366
1367 if (!this->badblock_pattern)
Brian Norris752ed6c2011-09-20 18:36:42 -07001368 nand_create_badblock_pattern(this);
Brian Norrisa2f812d2011-03-18 21:53:42 -07001369
David Woodhousee0c7d762006-05-13 18:07:53 +01001370 return nand_scan_bbt(mtd, this->badblock_pattern);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371}
1372
1373/**
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001374 * nand_isbad_bbt - [NAND Interface] Check if a block is bad
Brian Norris8b6e50c2011-05-25 14:59:01 -07001375 * @mtd: MTD device structure
1376 * @offs: offset in the device
1377 * @allowbbt: allow access to bad block table region
1378 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001379int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
1381 struct nand_chip *this = mtd->priv;
1382 int block;
David Woodhousee0c7d762006-05-13 18:07:53 +01001383 uint8_t res;
Thomas Gleixner61b03bd2005-11-07 11:15:49 +00001384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 /* Get block number * 2 */
David Woodhousee0c7d762006-05-13 18:07:53 +01001386 block = (int)(offs >> (this->bbt_erase_shift - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
1388
Brian Norris289c0522011-07-19 10:06:09 -07001389 pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
1390 "(block %d) 0x%02x\n",
1391 (unsigned int)offs, block >> 1, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 switch ((int)res) {
David Woodhousee0c7d762006-05-13 18:07:53 +01001394 case 0x00:
1395 return 0;
1396 case 0x01:
1397 return 1;
1398 case 0x02:
1399 return allowbbt ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 }
1401 return 1;
1402}
1403
David Woodhousee0c7d762006-05-13 18:07:53 +01001404EXPORT_SYMBOL(nand_scan_bbt);
1405EXPORT_SYMBOL(nand_default_bbt);