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