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