1 /* $NetBSD: nand_bbt.c,v 1.8 2018/02/08 07:48:19 mrg Exp $ */
2
3 /*-
4 * Copyright (c) 2011 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2011 Adam Hoka <ahoka@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 /*
35 * Implementation of Bad Block Tables (BBTs).
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: nand_bbt.c,v 1.8 2018/02/08 07:48:19 mrg Exp $");
40
41 #include <sys/param.h>
42 #include <sys/kmem.h>
43
44 #include "nand.h"
45 #include "nand_bbt.h"
46
47 void
48 nand_bbt_init(device_t self)
49 {
50 struct nand_softc *sc = device_private(self);
51 struct nand_chip *chip = &sc->sc_chip;
52 struct nand_bbt *bbt = &sc->sc_bbt;
53
54 bbt->nbbt_size = chip->nc_size / chip->nc_block_size / 4;
55 bbt->nbbt_bitmap = kmem_alloc(bbt->nbbt_size, KM_SLEEP);
56
57 memset(bbt->nbbt_bitmap, 0xff, bbt->nbbt_size);
58 }
59
60 void
61 nand_bbt_detach(device_t self)
62 {
63 struct nand_softc *sc = device_private(self);
64 struct nand_bbt *bbt = &sc->sc_bbt;
65
66 kmem_free(bbt->nbbt_bitmap, bbt->nbbt_size);
67 }
68
69 void
70 nand_bbt_scan(device_t self)
71 {
72 struct nand_softc *sc = device_private(self);
73 struct nand_chip *chip = &sc->sc_chip;
74 flash_off_t i, blocks, addr;
75
76 blocks = chip->nc_size / chip->nc_block_size;
77
78 aprint_normal_dev(self, "scanning for bad blocks\n");
79
80 addr = 0;
81 for (i = 0; i < blocks; i++) {
82 if (nand_isfactorybad(self, addr)) {
83 nand_bbt_block_markfactorybad(self, i);
84 } else if (nand_iswornoutbad(self, addr)) {
85 nand_bbt_block_markbad(self, i);
86 }
87
88 addr += chip->nc_block_size;
89 }
90 }
91
92 bool
93 nand_bbt_update(device_t self)
94 {
95 return true;
96 }
97
98 static bool
99 nand_bbt_page_has_bbt(device_t self, flash_off_t addr) {
100 struct nand_softc *sc = device_private(self);
101 struct nand_chip *chip = &sc->sc_chip;
102 uint8_t *oob = chip->nc_oob_cache;
103
104 nand_read_oob(self, addr, oob);
105
106 if (oob[NAND_BBT_OFFSET] == 'B' &&
107 oob[NAND_BBT_OFFSET + 1] == 'b' &&
108 oob[NAND_BBT_OFFSET + 2] == 't') {
109 return true;
110 } else {
111 return false;
112 }
113 }
114
115 static bool
116 nand_bbt_get_bbt_from_page(device_t self, flash_off_t addr)
117 {
118 struct nand_softc *sc = device_private(self);
119 struct nand_chip *chip = &sc->sc_chip;
120 struct nand_bbt *bbt = &sc->sc_bbt;
121 uint8_t *bbtp, *buf = chip->nc_page_cache;
122 size_t left, bbt_pages, i;
123
124 bbt_pages = bbt->nbbt_size / chip->nc_page_size;
125 if (bbt->nbbt_size % chip->nc_page_size)
126 bbt_pages++;
127
128 if (nand_isbad(self, addr)) {
129 return false;
130 }
131
132 if (nand_bbt_page_has_bbt(self, addr)) {
133 bbtp = bbt->nbbt_bitmap;
134 left = bbt->nbbt_size;
135
136 for (i = 0; i < bbt_pages; i++) {
137 nand_read_page(self, addr, buf);
138
139 if (i == bbt_pages - 1) {
140 KASSERT(left <= chip->nc_page_size);
141 memcpy(bbtp, buf, left);
142 } else {
143 memcpy(bbtp, buf, chip->nc_page_size);
144 }
145
146 bbtp += chip->nc_page_size;
147 left -= chip->nc_page_size;
148 addr += chip->nc_page_size;
149 }
150
151 return true;
152 } else {
153 return false;
154 }
155 }
156
157 bool
158 nand_bbt_load(device_t self)
159 {
160 struct nand_softc *sc = device_private(self);
161 struct nand_chip *chip = &sc->sc_chip;
162 flash_off_t blockaddr;
163 int n;
164
165 blockaddr = chip->nc_size - chip->nc_block_size;
166 /* XXX currently we check the last 4 blocks */
167 for (n = 0; n < 4; n++) {
168 if (nand_bbt_get_bbt_from_page(self, blockaddr)) {
169 break;
170 } else {
171 blockaddr -= chip->nc_block_size;
172 }
173 }
174
175 return true;
176 }
177
178 void
179 nand_bbt_block_markbad(device_t self, flash_off_t block)
180 {
181 if (nand_bbt_block_isbad(self, block)) {
182 aprint_error_dev(self,
183 "trying to mark block bad already marked in bbt\n");
184 }
185 /* XXX check if this is the correct marker */
186 nand_bbt_block_mark(self, block, NAND_BBT_MARKER_WORNOUT_BAD);
187 }
188
189 void
190 nand_bbt_block_markfactorybad(device_t self, flash_off_t block)
191 {
192 if (nand_bbt_block_isbad(self, block)) {
193 aprint_error_dev(self,
194 "trying to mark block factory bad already"
195 " marked in bbt\n");
196 }
197 nand_bbt_block_mark(self, block, NAND_BBT_MARKER_FACTORY_BAD);
198 }
199
200 void
201 nand_bbt_block_mark(device_t self, flash_off_t block, uint8_t marker)
202 {
203 struct nand_softc *sc = device_private(self);
204 struct nand_chip *chip = &sc->sc_chip;
205 struct nand_bbt *bbt = &sc->sc_bbt;
206 uint8_t clean;
207
208 __USE(chip);
209 KASSERT(block < chip->nc_size / chip->nc_block_size);
210
211 clean = (0xfc << ((block % 4) * 2));
212 marker = (marker << ((block % 4) * 2));
213
214 /* set byte containing the 2 bit marker for this block */
215 bbt->nbbt_bitmap[block / 4] &= clean;
216 bbt->nbbt_bitmap[block / 4] |= marker;
217 }
218
219 bool
220 nand_bbt_block_isbad(device_t self, flash_off_t block)
221 {
222 struct nand_softc *sc = device_private(self);
223 struct nand_chip *chip = &sc->sc_chip;
224 struct nand_bbt *bbt = &sc->sc_bbt;
225 uint8_t byte, marker;
226 bool result;
227
228 __USE(chip);
229 KASSERT(block < chip->nc_size / chip->nc_block_size);
230
231 /* get byte containing the 2 bit marker for this block */
232 byte = bbt->nbbt_bitmap[block / 4];
233
234 /* extract the 2 bit marker from the byte */
235 marker = (byte >> ((block % 4) * 2)) & 0x03;
236
237 switch (marker) {
238 case NAND_BBT_MARKER_FACTORY_BAD:
239 case NAND_BBT_MARKER_WORNOUT_BAD:
240 case NAND_BBT_MARKER_RESERVED:
241 result = true;
242 break;
243 case NAND_BBT_MARKER_GOOD:
244 result = false;
245 break;
246 default:
247 panic("error in marker extraction");
248 }
249
250 return result;
251 }
Cache object: 748af621d60ca15381aa2b7b156f8ef5
|