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