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