Home | History | Annotate | Line # | Download | only in nand
nand_bbt.c revision 1.1
      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 (at) 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