nand_bbt.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009-2012 Semihalf
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: stable/11/sys/dev/nand/nand_bbt.c 330897 2018-03-14 03:19:51Z eadler $
29 */
30
31#include <sys/cdefs.h>
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/socket.h>
37#include <sys/malloc.h>
38#include <sys/bus.h>
39
40#include <dev/nand/nand.h>
41
42#include "nand_if.h"
43
44#define BBT_PRIMARY_PATTERN	0x01020304
45#define BBT_SECONDARY_PATTERN	0x05060708
46
47enum bbt_place {
48	BBT_NONE,
49	BBT_PRIMARY,
50	BBT_SECONDARY
51};
52
53struct nand_bbt {
54	struct nand_chip	*chip;
55	uint32_t		primary_map;
56	uint32_t		secondary_map;
57	enum bbt_place		active;
58	struct bbt_header	*hdr;
59	uint32_t		tab_len;
60	uint32_t		*table;
61};
62
63struct bbt_header {
64	uint32_t pattern;
65	int32_t seq_nr;
66};
67
68static int nand_bbt_save(struct nand_bbt *);
69static int nand_bbt_load_hdr(struct nand_bbt *, struct bbt_header *, int8_t);
70static int nand_bbt_load_table(struct nand_bbt *);
71static int nand_bbt_prescan(struct nand_bbt *);
72
73int
74nand_init_bbt(struct nand_chip *chip)
75{
76	struct chip_geom *cg;
77	struct nand_bbt *bbt;
78	int err;
79
80	cg = &chip->chip_geom;
81
82	bbt = malloc(sizeof(struct nand_bbt), M_NAND, M_ZERO | M_WAITOK);
83	if (!bbt) {
84		device_printf(chip->dev,
85		    "Cannot allocate memory for bad block struct");
86		return (ENOMEM);
87	}
88
89	bbt->chip = chip;
90	bbt->active = BBT_NONE;
91	bbt->primary_map = cg->chip_size - cg->block_size;
92	bbt->secondary_map = cg->chip_size - 2 * cg->block_size;
93	bbt->tab_len = cg->blks_per_chip * sizeof(uint32_t);
94	bbt->hdr = malloc(sizeof(struct bbt_header) + bbt->tab_len, M_NAND,
95	    M_WAITOK);
96	if (!bbt->hdr) {
97		device_printf(chip->dev, "Cannot allocate %d bytes for BB "
98		    "Table", bbt->tab_len);
99		free(bbt, M_NAND);
100		return (ENOMEM);
101	}
102	bbt->hdr->seq_nr = 0;
103	bbt->table = (uint32_t *)((uint8_t *)bbt->hdr +
104	    sizeof(struct bbt_header));
105
106	err = nand_bbt_load_table(bbt);
107	if (err) {
108		free(bbt->table, M_NAND);
109		free(bbt, M_NAND);
110		return (err);
111	}
112
113	chip->bbt = bbt;
114	if (bbt->active == BBT_NONE) {
115		bbt->active = BBT_PRIMARY;
116		memset(bbt->table, 0xff, bbt->tab_len);
117		nand_bbt_prescan(bbt);
118		nand_bbt_save(bbt);
119	} else
120		device_printf(chip->dev, "Found BBT table for chip\n");
121
122	return (0);
123}
124
125void
126nand_destroy_bbt(struct nand_chip *chip)
127{
128
129	if (chip->bbt) {
130		nand_bbt_save(chip->bbt);
131
132		free(chip->bbt->hdr, M_NAND);
133		free(chip->bbt, M_NAND);
134		chip->bbt = NULL;
135	}
136}
137
138int
139nand_update_bbt(struct nand_chip *chip)
140{
141
142	nand_bbt_save(chip->bbt);
143
144	return (0);
145}
146
147static int
148nand_bbt_save(struct nand_bbt *bbt)
149{
150	enum bbt_place next;
151	uint32_t addr;
152	int32_t err;
153
154	if (bbt->active == BBT_PRIMARY) {
155		addr = bbt->secondary_map;
156		bbt->hdr->pattern = BBT_SECONDARY_PATTERN;
157		next = BBT_SECONDARY;
158	} else {
159		addr = bbt->primary_map;
160		bbt->hdr->pattern = BBT_PRIMARY_PATTERN;
161		next = BBT_PRIMARY;
162	}
163
164	err = nand_erase_blocks(bbt->chip, addr,
165	    bbt->chip->chip_geom.block_size);
166	if (err)
167		return (err);
168
169	bbt->hdr->seq_nr++;
170
171	err = nand_prog_pages_raw(bbt->chip, addr, bbt->hdr,
172	    bbt->tab_len + sizeof(struct bbt_header));
173	if (err)
174		return (err);
175
176	bbt->active = next;
177	return (0);
178}
179
180static int
181nand_bbt_load_hdr(struct nand_bbt *bbt, struct bbt_header *hdr, int8_t primary)
182{
183	uint32_t addr;
184
185	if (primary)
186		addr = bbt->primary_map;
187	else
188		addr = bbt->secondary_map;
189
190	return (nand_read_pages_raw(bbt->chip, addr, hdr,
191	    sizeof(struct bbt_header)));
192}
193
194static int
195nand_bbt_load_table(struct nand_bbt *bbt)
196{
197	struct bbt_header hdr1, hdr2;
198	uint32_t address = 0;
199	int err = 0;
200
201	bzero(&hdr1, sizeof(hdr1));
202	bzero(&hdr2, sizeof(hdr2));
203
204	nand_bbt_load_hdr(bbt, &hdr1, 1);
205	if (hdr1.pattern == BBT_PRIMARY_PATTERN) {
206		bbt->active = BBT_PRIMARY;
207		address = bbt->primary_map;
208	} else
209		bzero(&hdr1, sizeof(hdr1));
210
211
212	nand_bbt_load_hdr(bbt, &hdr2, 0);
213	if ((hdr2.pattern == BBT_SECONDARY_PATTERN) &&
214	    (hdr2.seq_nr > hdr1.seq_nr)) {
215		bbt->active = BBT_SECONDARY;
216		address = bbt->secondary_map;
217	} else
218		bzero(&hdr2, sizeof(hdr2));
219
220	if (bbt->active != BBT_NONE)
221		err = nand_read_pages_raw(bbt->chip, address, bbt->hdr,
222		    bbt->tab_len + sizeof(struct bbt_header));
223
224	return (err);
225}
226
227static int
228nand_bbt_prescan(struct nand_bbt *bbt)
229{
230	int32_t i;
231	uint8_t bad;
232	bool printed_hash = 0;
233
234	device_printf(bbt->chip->dev, "No BBT found. Prescan chip...\n");
235	for (i = 0; i < bbt->chip->chip_geom.blks_per_chip; i++) {
236		if (NAND_IS_BLK_BAD(bbt->chip->dev, i, &bad))
237			return (ENXIO);
238
239		if (bad) {
240			device_printf(bbt->chip->dev, "Bad block(%d)\n", i);
241			bbt->table[i] = 0x0FFFFFFF;
242		}
243		if (!(i % 100)) {
244			printf("#");
245			printed_hash = 1;
246		}
247	}
248
249	if (printed_hash)
250		printf("\n");
251
252	return (0);
253}
254
255int
256nand_check_bad_block(struct nand_chip *chip, uint32_t block_number)
257{
258
259	if (!chip || !chip->bbt)
260		return (0);
261
262	if ((chip->bbt->table[block_number] & 0xF0000000) == 0)
263		return (1);
264
265	return (0);
266}
267
268int
269nand_mark_bad_block(struct nand_chip *chip, uint32_t block_number)
270{
271
272	chip->bbt->table[block_number] = 0x0FFFFFFF;
273
274	return (0);
275}
276