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