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