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