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@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