Home | History | Annotate | Line # | Download | only in nand
nand_bbt.c revision 1.1
      1  1.1  ahoka /*	$NetBSD: nand_bbt.c,v 1.1 2011/02/26 18:07:31 ahoka 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.1  ahoka /* Support for Bad Block Tables (BBTs) */
     35  1.1  ahoka 
     36  1.1  ahoka #include <sys/param.h>
     37  1.1  ahoka #include <sys/kmem.h>
     38  1.1  ahoka 
     39  1.1  ahoka #include "nand.h"
     40  1.1  ahoka #include "nand_bbt.h"
     41  1.1  ahoka 
     42  1.1  ahoka void
     43  1.1  ahoka nand_bbt_init(device_t self)
     44  1.1  ahoka {
     45  1.1  ahoka 	struct nand_softc *sc = device_private(self);
     46  1.1  ahoka 	struct nand_chip *chip = &sc->sc_chip;
     47  1.1  ahoka 	struct nand_bbt *bbt = &sc->sc_bbt;
     48  1.1  ahoka 
     49  1.1  ahoka 	bbt->nbbt_size = chip->nc_size / chip->nc_block_size / 4;
     50  1.1  ahoka 	bbt->nbbt_bitmap = kmem_alloc(bbt->nbbt_size, KM_SLEEP);
     51  1.1  ahoka 
     52  1.1  ahoka 	memset(bbt->nbbt_bitmap, 0xff, bbt->nbbt_size);
     53  1.1  ahoka }
     54  1.1  ahoka 
     55  1.1  ahoka void
     56  1.1  ahoka nand_bbt_detach(device_t self)
     57  1.1  ahoka {
     58  1.1  ahoka 	struct nand_softc *sc = device_private(self);
     59  1.1  ahoka 	struct nand_bbt *bbt = &sc->sc_bbt;
     60  1.1  ahoka 
     61  1.1  ahoka 	printf("freeing bbt bitmap...");
     62  1.1  ahoka 	kmem_free(bbt->nbbt_bitmap, bbt->nbbt_size);
     63  1.1  ahoka 	printf("done!\n");
     64  1.1  ahoka }
     65  1.1  ahoka 
     66  1.1  ahoka void
     67  1.1  ahoka nand_bbt_scan(device_t self)
     68  1.1  ahoka {
     69  1.1  ahoka 	struct nand_softc *sc = device_private(self);
     70  1.1  ahoka 	struct nand_chip *chip = &sc->sc_chip;
     71  1.1  ahoka 	flash_addr_t i, blocks, addr;
     72  1.1  ahoka 
     73  1.1  ahoka 	blocks = chip->nc_size / chip->nc_block_size;
     74  1.1  ahoka 
     75  1.1  ahoka 	aprint_normal_dev(self, "scanning for bad blocks\n");
     76  1.1  ahoka 
     77  1.1  ahoka 	addr = 0;
     78  1.1  ahoka 	for (i = 0; i < blocks; i++) {
     79  1.1  ahoka 		if (nand_isfactorybad(self, addr)) {
     80  1.1  ahoka 			nand_bbt_block_markfactorybad(self, i);
     81  1.1  ahoka 		} else if (nand_iswornoutbad(self, addr)) {
     82  1.1  ahoka 			nand_bbt_block_markbad(self, i);
     83  1.1  ahoka 		}
     84  1.1  ahoka 
     85  1.1  ahoka 		addr += chip->nc_block_size;
     86  1.1  ahoka 	}
     87  1.1  ahoka }
     88  1.1  ahoka 
     89  1.1  ahoka bool
     90  1.1  ahoka nand_bbt_update(device_t self)
     91  1.1  ahoka {
     92  1.1  ahoka 	return true;
     93  1.1  ahoka }
     94  1.1  ahoka 
     95  1.1  ahoka static bool
     96  1.1  ahoka nand_bbt_page_has_bbt(device_t self, flash_addr_t addr) {
     97  1.1  ahoka 	struct nand_softc *sc = device_private(self);
     98  1.1  ahoka 	struct nand_chip *chip = &sc->sc_chip;
     99  1.1  ahoka 	uint8_t *oob = chip->nc_oob_cache;
    100  1.1  ahoka 
    101  1.1  ahoka 	nand_read_oob(self, addr, oob);
    102  1.1  ahoka 
    103  1.1  ahoka 	if (oob[NAND_BBT_OFFSET] == 'B' &&
    104  1.1  ahoka 	    oob[NAND_BBT_OFFSET + 1] == 'b' &&
    105  1.1  ahoka 	    oob[NAND_BBT_OFFSET + 2] == 't') {
    106  1.1  ahoka 		return true;
    107  1.1  ahoka 	} else {
    108  1.1  ahoka 		return false;
    109  1.1  ahoka 	}
    110  1.1  ahoka }
    111  1.1  ahoka 
    112  1.1  ahoka static bool
    113  1.1  ahoka nand_bbt_get_bbt_from_page(device_t self, flash_addr_t addr)
    114  1.1  ahoka {
    115  1.1  ahoka 	struct nand_softc *sc = device_private(self);
    116  1.1  ahoka 	struct nand_chip *chip = &sc->sc_chip;
    117  1.1  ahoka 	struct nand_bbt *bbt = &sc->sc_bbt;
    118  1.1  ahoka 	uint8_t *bbtp, *buf = chip->nc_page_cache;
    119  1.1  ahoka 	size_t left, bbt_pages, i;
    120  1.1  ahoka 
    121  1.1  ahoka 	bbt_pages = bbt->nbbt_size / chip->nc_page_size;
    122  1.1  ahoka 	if (bbt->nbbt_size % chip->nc_page_size)
    123  1.1  ahoka 		bbt_pages++;
    124  1.1  ahoka 
    125  1.1  ahoka 	if (nand_isbad(self, addr)) {
    126  1.1  ahoka 		return false;
    127  1.1  ahoka 	}
    128  1.1  ahoka 
    129  1.1  ahoka 	if (nand_bbt_page_has_bbt(self, addr)) {
    130  1.1  ahoka 		bbtp = bbt->nbbt_bitmap;
    131  1.1  ahoka 		left = bbt->nbbt_size;
    132  1.1  ahoka 
    133  1.1  ahoka 		for (i = 0; i < bbt_pages; i++) {
    134  1.1  ahoka 			nand_read_page(self, addr, buf);
    135  1.1  ahoka 
    136  1.1  ahoka 			if (i == bbt_pages - 1) {
    137  1.1  ahoka 				KASSERT(left <= chip->nc_page_size);
    138  1.1  ahoka 				memcpy(bbtp, buf, left);
    139  1.1  ahoka 			} else {
    140  1.1  ahoka 				memcpy(bbtp, buf, chip->nc_page_size);
    141  1.1  ahoka 			}
    142  1.1  ahoka 
    143  1.1  ahoka 			bbtp += chip->nc_page_size;
    144  1.1  ahoka 			left -= chip->nc_page_size;
    145  1.1  ahoka 			addr += chip->nc_page_size;
    146  1.1  ahoka 		}
    147  1.1  ahoka 
    148  1.1  ahoka 		return true;
    149  1.1  ahoka 	} else {
    150  1.1  ahoka 		return false;
    151  1.1  ahoka 	}
    152  1.1  ahoka }
    153  1.1  ahoka 
    154  1.1  ahoka bool
    155  1.1  ahoka nand_bbt_load(device_t self)
    156  1.1  ahoka {
    157  1.1  ahoka 	struct nand_softc *sc = device_private(self);
    158  1.1  ahoka 	struct nand_chip *chip = &sc->sc_chip;
    159  1.1  ahoka 	flash_addr_t blockaddr;
    160  1.1  ahoka 	int n;
    161  1.1  ahoka 
    162  1.1  ahoka 	blockaddr = chip->nc_size - chip->nc_block_size;
    163  1.1  ahoka 	/* XXX currently we check the last 4 blocks */
    164  1.1  ahoka 	for (n = 0; n < 4; n++) {
    165  1.1  ahoka 		if (nand_bbt_get_bbt_from_page(self, blockaddr)) {
    166  1.1  ahoka 			break;
    167  1.1  ahoka 		} else {
    168  1.1  ahoka 			blockaddr -= chip->nc_block_size;
    169  1.1  ahoka 		}
    170  1.1  ahoka 	}
    171  1.1  ahoka 
    172  1.1  ahoka 	return true;
    173  1.1  ahoka }
    174  1.1  ahoka 
    175  1.1  ahoka void
    176  1.1  ahoka nand_bbt_block_markbad(device_t self, flash_addr_t block)
    177  1.1  ahoka {
    178  1.1  ahoka 	if (nand_bbt_block_isbad(self, block)) {
    179  1.1  ahoka 		aprint_error_dev(self,
    180  1.1  ahoka 		    "trying to mark block bad already marked in bbt\n");
    181  1.1  ahoka 	}
    182  1.1  ahoka 	/* XXX check if this is the correct marker */
    183  1.1  ahoka 	nand_bbt_block_mark(self, block, NAND_BBT_MARKER_WORNOUT_BAD);
    184  1.1  ahoka }
    185  1.1  ahoka 
    186  1.1  ahoka void
    187  1.1  ahoka nand_bbt_block_markfactorybad(device_t self, flash_addr_t block)
    188  1.1  ahoka {
    189  1.1  ahoka 	if (nand_bbt_block_isbad(self, block)) {
    190  1.1  ahoka 		aprint_error_dev(self,
    191  1.1  ahoka 		    "trying to mark block factory bad already"
    192  1.1  ahoka 		    " marked in bbt\n");
    193  1.1  ahoka 	}
    194  1.1  ahoka 	nand_bbt_block_mark(self, block, NAND_BBT_MARKER_FACTORY_BAD);
    195  1.1  ahoka }
    196  1.1  ahoka 
    197  1.1  ahoka void
    198  1.1  ahoka nand_bbt_block_mark(device_t self, flash_addr_t block, uint8_t marker)
    199  1.1  ahoka {
    200  1.1  ahoka 	struct nand_softc *sc = device_private(self);
    201  1.1  ahoka #ifdef DIAGNOSTIC
    202  1.1  ahoka 	struct nand_chip *chip = &sc->sc_chip;
    203  1.1  ahoka #endif
    204  1.1  ahoka 	struct nand_bbt *bbt = &sc->sc_bbt;
    205  1.1  ahoka 	uint8_t clean;
    206  1.1  ahoka 
    207  1.1  ahoka 	KASSERT(block < chip->nc_size / chip->nc_block_size);
    208  1.1  ahoka 
    209  1.1  ahoka 	clean = (~0x03 << ((block % 4) * 2));
    210  1.1  ahoka 	marker = (marker << ((block % 4) * 2));
    211  1.1  ahoka 
    212  1.1  ahoka 	/* set byte containing the 2 bit marker for this block */
    213  1.1  ahoka 	bbt->nbbt_bitmap[block / 4] &= clean;
    214  1.1  ahoka 	bbt->nbbt_bitmap[block / 4] |= marker;
    215  1.1  ahoka }
    216  1.1  ahoka 
    217  1.1  ahoka bool
    218  1.1  ahoka nand_bbt_block_isbad(device_t self, flash_addr_t block)
    219  1.1  ahoka {
    220  1.1  ahoka 	struct nand_softc *sc = device_private(self);
    221  1.1  ahoka #ifdef DIAGNOSTIC
    222  1.1  ahoka 	struct nand_chip *chip = &sc->sc_chip;
    223  1.1  ahoka #endif
    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.1  ahoka 	KASSERT(block < chip->nc_size / chip->nc_block_size);
    229  1.1  ahoka 
    230  1.1  ahoka 	/* get byte containing the 2 bit marker for this block */
    231  1.1  ahoka 	byte = bbt->nbbt_bitmap[block / 4];
    232  1.1  ahoka 
    233  1.1  ahoka 	/* extract the 2 bit marker from the byte */
    234  1.1  ahoka 	marker = (byte >> ((block % 4) * 2)) & 0x03;
    235  1.1  ahoka 
    236  1.1  ahoka 	switch (marker) {
    237  1.1  ahoka 	case NAND_BBT_MARKER_FACTORY_BAD:
    238  1.1  ahoka 	case NAND_BBT_MARKER_WORNOUT_BAD:
    239  1.1  ahoka 	case NAND_BBT_MARKER_RESERVED:
    240  1.1  ahoka 		result = true;
    241  1.1  ahoka 		break;
    242  1.1  ahoka 	case NAND_BBT_MARKER_GOOD:
    243  1.1  ahoka 		result = false;
    244  1.1  ahoka 		break;
    245  1.1  ahoka 	default:
    246  1.1  ahoka 		panic("error in marker extraction");
    247  1.1  ahoka 	}
    248  1.1  ahoka 
    249  1.1  ahoka 	return result;
    250  1.1  ahoka }
    251