nand_bbt.c revision 1.1 1 /* $NetBSD: nand_bbt.c,v 1.1 2011/02/26 18:07:31 ahoka Exp $ */
2
3 /*-
4 * Copyright (c) 2011 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2011 Adam Hoka <ahoka (at) NetBSD.org>
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by the Department of Software Engineering, University of Szeged, Hungary
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /* Support for Bad Block Tables (BBTs) */
35
36 #include <sys/param.h>
37 #include <sys/kmem.h>
38
39 #include "nand.h"
40 #include "nand_bbt.h"
41
42 void
43 nand_bbt_init(device_t self)
44 {
45 struct nand_softc *sc = device_private(self);
46 struct nand_chip *chip = &sc->sc_chip;
47 struct nand_bbt *bbt = &sc->sc_bbt;
48
49 bbt->nbbt_size = chip->nc_size / chip->nc_block_size / 4;
50 bbt->nbbt_bitmap = kmem_alloc(bbt->nbbt_size, KM_SLEEP);
51
52 memset(bbt->nbbt_bitmap, 0xff, bbt->nbbt_size);
53 }
54
55 void
56 nand_bbt_detach(device_t self)
57 {
58 struct nand_softc *sc = device_private(self);
59 struct nand_bbt *bbt = &sc->sc_bbt;
60
61 printf("freeing bbt bitmap...");
62 kmem_free(bbt->nbbt_bitmap, bbt->nbbt_size);
63 printf("done!\n");
64 }
65
66 void
67 nand_bbt_scan(device_t self)
68 {
69 struct nand_softc *sc = device_private(self);
70 struct nand_chip *chip = &sc->sc_chip;
71 flash_addr_t i, blocks, addr;
72
73 blocks = chip->nc_size / chip->nc_block_size;
74
75 aprint_normal_dev(self, "scanning for bad blocks\n");
76
77 addr = 0;
78 for (i = 0; i < blocks; i++) {
79 if (nand_isfactorybad(self, addr)) {
80 nand_bbt_block_markfactorybad(self, i);
81 } else if (nand_iswornoutbad(self, addr)) {
82 nand_bbt_block_markbad(self, i);
83 }
84
85 addr += chip->nc_block_size;
86 }
87 }
88
89 bool
90 nand_bbt_update(device_t self)
91 {
92 return true;
93 }
94
95 static bool
96 nand_bbt_page_has_bbt(device_t self, flash_addr_t addr) {
97 struct nand_softc *sc = device_private(self);
98 struct nand_chip *chip = &sc->sc_chip;
99 uint8_t *oob = chip->nc_oob_cache;
100
101 nand_read_oob(self, addr, oob);
102
103 if (oob[NAND_BBT_OFFSET] == 'B' &&
104 oob[NAND_BBT_OFFSET + 1] == 'b' &&
105 oob[NAND_BBT_OFFSET + 2] == 't') {
106 return true;
107 } else {
108 return false;
109 }
110 }
111
112 static bool
113 nand_bbt_get_bbt_from_page(device_t self, flash_addr_t addr)
114 {
115 struct nand_softc *sc = device_private(self);
116 struct nand_chip *chip = &sc->sc_chip;
117 struct nand_bbt *bbt = &sc->sc_bbt;
118 uint8_t *bbtp, *buf = chip->nc_page_cache;
119 size_t left, bbt_pages, i;
120
121 bbt_pages = bbt->nbbt_size / chip->nc_page_size;
122 if (bbt->nbbt_size % chip->nc_page_size)
123 bbt_pages++;
124
125 if (nand_isbad(self, addr)) {
126 return false;
127 }
128
129 if (nand_bbt_page_has_bbt(self, addr)) {
130 bbtp = bbt->nbbt_bitmap;
131 left = bbt->nbbt_size;
132
133 for (i = 0; i < bbt_pages; i++) {
134 nand_read_page(self, addr, buf);
135
136 if (i == bbt_pages - 1) {
137 KASSERT(left <= chip->nc_page_size);
138 memcpy(bbtp, buf, left);
139 } else {
140 memcpy(bbtp, buf, chip->nc_page_size);
141 }
142
143 bbtp += chip->nc_page_size;
144 left -= chip->nc_page_size;
145 addr += chip->nc_page_size;
146 }
147
148 return true;
149 } else {
150 return false;
151 }
152 }
153
154 bool
155 nand_bbt_load(device_t self)
156 {
157 struct nand_softc *sc = device_private(self);
158 struct nand_chip *chip = &sc->sc_chip;
159 flash_addr_t blockaddr;
160 int n;
161
162 blockaddr = chip->nc_size - chip->nc_block_size;
163 /* XXX currently we check the last 4 blocks */
164 for (n = 0; n < 4; n++) {
165 if (nand_bbt_get_bbt_from_page(self, blockaddr)) {
166 break;
167 } else {
168 blockaddr -= chip->nc_block_size;
169 }
170 }
171
172 return true;
173 }
174
175 void
176 nand_bbt_block_markbad(device_t self, flash_addr_t block)
177 {
178 if (nand_bbt_block_isbad(self, block)) {
179 aprint_error_dev(self,
180 "trying to mark block bad already marked in bbt\n");
181 }
182 /* XXX check if this is the correct marker */
183 nand_bbt_block_mark(self, block, NAND_BBT_MARKER_WORNOUT_BAD);
184 }
185
186 void
187 nand_bbt_block_markfactorybad(device_t self, flash_addr_t block)
188 {
189 if (nand_bbt_block_isbad(self, block)) {
190 aprint_error_dev(self,
191 "trying to mark block factory bad already"
192 " marked in bbt\n");
193 }
194 nand_bbt_block_mark(self, block, NAND_BBT_MARKER_FACTORY_BAD);
195 }
196
197 void
198 nand_bbt_block_mark(device_t self, flash_addr_t block, uint8_t marker)
199 {
200 struct nand_softc *sc = device_private(self);
201 #ifdef DIAGNOSTIC
202 struct nand_chip *chip = &sc->sc_chip;
203 #endif
204 struct nand_bbt *bbt = &sc->sc_bbt;
205 uint8_t clean;
206
207 KASSERT(block < chip->nc_size / chip->nc_block_size);
208
209 clean = (~0x03 << ((block % 4) * 2));
210 marker = (marker << ((block % 4) * 2));
211
212 /* set byte containing the 2 bit marker for this block */
213 bbt->nbbt_bitmap[block / 4] &= clean;
214 bbt->nbbt_bitmap[block / 4] |= marker;
215 }
216
217 bool
218 nand_bbt_block_isbad(device_t self, flash_addr_t block)
219 {
220 struct nand_softc *sc = device_private(self);
221 #ifdef DIAGNOSTIC
222 struct nand_chip *chip = &sc->sc_chip;
223 #endif
224 struct nand_bbt *bbt = &sc->sc_bbt;
225 uint8_t byte, marker;
226 bool result;
227
228 KASSERT(block < chip->nc_size / chip->nc_block_size);
229
230 /* get byte containing the 2 bit marker for this block */
231 byte = bbt->nbbt_bitmap[block / 4];
232
233 /* extract the 2 bit marker from the byte */
234 marker = (byte >> ((block % 4) * 2)) & 0x03;
235
236 switch (marker) {
237 case NAND_BBT_MARKER_FACTORY_BAD:
238 case NAND_BBT_MARKER_WORNOUT_BAD:
239 case NAND_BBT_MARKER_RESERVED:
240 result = true;
241 break;
242 case NAND_BBT_MARKER_GOOD:
243 result = false;
244 break;
245 default:
246 panic("error in marker extraction");
247 }
248
249 return result;
250 }
251