1*df8b6b33Smrg /* $NetBSD: nand_bbt.c,v 1.8 2018/02/08 07:48:19 mrg Exp $ */
22b6ee221Sahoka
32b6ee221Sahoka /*-
42b6ee221Sahoka * Copyright (c) 2011 Department of Software Engineering,
52b6ee221Sahoka * University of Szeged, Hungary
62b6ee221Sahoka * Copyright (c) 2011 Adam Hoka <ahoka@NetBSD.org>
72b6ee221Sahoka * All rights reserved.
82b6ee221Sahoka *
92b6ee221Sahoka * This code is derived from software contributed to The NetBSD Foundation
102b6ee221Sahoka * by the Department of Software Engineering, University of Szeged, Hungary
112b6ee221Sahoka *
122b6ee221Sahoka * Redistribution and use in source and binary forms, with or without
132b6ee221Sahoka * modification, are permitted provided that the following conditions
142b6ee221Sahoka * are met:
152b6ee221Sahoka * 1. Redistributions of source code must retain the above copyright
162b6ee221Sahoka * notice, this list of conditions and the following disclaimer.
172b6ee221Sahoka * 2. Redistributions in binary form must reproduce the above copyright
182b6ee221Sahoka * notice, this list of conditions and the following disclaimer in the
192b6ee221Sahoka * documentation and/or other materials provided with the distribution.
202b6ee221Sahoka *
212b6ee221Sahoka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
222b6ee221Sahoka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
232b6ee221Sahoka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
242b6ee221Sahoka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
252b6ee221Sahoka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
262b6ee221Sahoka * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
272b6ee221Sahoka * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
282b6ee221Sahoka * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
292b6ee221Sahoka * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
302b6ee221Sahoka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
312b6ee221Sahoka * SUCH DAMAGE.
322b6ee221Sahoka */
332b6ee221Sahoka
349cc6428eSrmind /*
359cc6428eSrmind * Implementation of Bad Block Tables (BBTs).
369cc6428eSrmind */
379cc6428eSrmind
389cc6428eSrmind #include <sys/cdefs.h>
39*df8b6b33Smrg __KERNEL_RCSID(0, "$NetBSD: nand_bbt.c,v 1.8 2018/02/08 07:48:19 mrg Exp $");
402b6ee221Sahoka
412b6ee221Sahoka #include <sys/param.h>
422b6ee221Sahoka #include <sys/kmem.h>
432b6ee221Sahoka
442b6ee221Sahoka #include "nand.h"
452b6ee221Sahoka #include "nand_bbt.h"
462b6ee221Sahoka
472b6ee221Sahoka void
nand_bbt_init(device_t self)482b6ee221Sahoka nand_bbt_init(device_t self)
492b6ee221Sahoka {
502b6ee221Sahoka struct nand_softc *sc = device_private(self);
512b6ee221Sahoka struct nand_chip *chip = &sc->sc_chip;
522b6ee221Sahoka struct nand_bbt *bbt = &sc->sc_bbt;
532b6ee221Sahoka
542b6ee221Sahoka bbt->nbbt_size = chip->nc_size / chip->nc_block_size / 4;
552b6ee221Sahoka bbt->nbbt_bitmap = kmem_alloc(bbt->nbbt_size, KM_SLEEP);
562b6ee221Sahoka
572b6ee221Sahoka memset(bbt->nbbt_bitmap, 0xff, bbt->nbbt_size);
582b6ee221Sahoka }
592b6ee221Sahoka
602b6ee221Sahoka void
nand_bbt_detach(device_t self)612b6ee221Sahoka nand_bbt_detach(device_t self)
622b6ee221Sahoka {
632b6ee221Sahoka struct nand_softc *sc = device_private(self);
642b6ee221Sahoka struct nand_bbt *bbt = &sc->sc_bbt;
652b6ee221Sahoka
662b6ee221Sahoka kmem_free(bbt->nbbt_bitmap, bbt->nbbt_size);
672b6ee221Sahoka }
682b6ee221Sahoka
692b6ee221Sahoka void
nand_bbt_scan(device_t self)702b6ee221Sahoka nand_bbt_scan(device_t self)
712b6ee221Sahoka {
722b6ee221Sahoka struct nand_softc *sc = device_private(self);
732b6ee221Sahoka struct nand_chip *chip = &sc->sc_chip;
746adb739dSahoka flash_off_t i, blocks, addr;
752b6ee221Sahoka
762b6ee221Sahoka blocks = chip->nc_size / chip->nc_block_size;
772b6ee221Sahoka
782b6ee221Sahoka aprint_normal_dev(self, "scanning for bad blocks\n");
792b6ee221Sahoka
802b6ee221Sahoka addr = 0;
812b6ee221Sahoka for (i = 0; i < blocks; i++) {
822b6ee221Sahoka if (nand_isfactorybad(self, addr)) {
832b6ee221Sahoka nand_bbt_block_markfactorybad(self, i);
842b6ee221Sahoka } else if (nand_iswornoutbad(self, addr)) {
852b6ee221Sahoka nand_bbt_block_markbad(self, i);
862b6ee221Sahoka }
872b6ee221Sahoka
882b6ee221Sahoka addr += chip->nc_block_size;
892b6ee221Sahoka }
902b6ee221Sahoka }
912b6ee221Sahoka
922b6ee221Sahoka bool
nand_bbt_update(device_t self)932b6ee221Sahoka nand_bbt_update(device_t self)
942b6ee221Sahoka {
952b6ee221Sahoka return true;
962b6ee221Sahoka }
972b6ee221Sahoka
982b6ee221Sahoka static bool
nand_bbt_page_has_bbt(device_t self,flash_off_t addr)996adb739dSahoka nand_bbt_page_has_bbt(device_t self, flash_off_t addr) {
1002b6ee221Sahoka struct nand_softc *sc = device_private(self);
1012b6ee221Sahoka struct nand_chip *chip = &sc->sc_chip;
1022b6ee221Sahoka uint8_t *oob = chip->nc_oob_cache;
1032b6ee221Sahoka
1042b6ee221Sahoka nand_read_oob(self, addr, oob);
1052b6ee221Sahoka
1062b6ee221Sahoka if (oob[NAND_BBT_OFFSET] == 'B' &&
1072b6ee221Sahoka oob[NAND_BBT_OFFSET + 1] == 'b' &&
1082b6ee221Sahoka oob[NAND_BBT_OFFSET + 2] == 't') {
1092b6ee221Sahoka return true;
1102b6ee221Sahoka } else {
1112b6ee221Sahoka return false;
1122b6ee221Sahoka }
1132b6ee221Sahoka }
1142b6ee221Sahoka
1152b6ee221Sahoka static bool
nand_bbt_get_bbt_from_page(device_t self,flash_off_t addr)1166adb739dSahoka nand_bbt_get_bbt_from_page(device_t self, flash_off_t addr)
1172b6ee221Sahoka {
1182b6ee221Sahoka struct nand_softc *sc = device_private(self);
1192b6ee221Sahoka struct nand_chip *chip = &sc->sc_chip;
1202b6ee221Sahoka struct nand_bbt *bbt = &sc->sc_bbt;
1212b6ee221Sahoka uint8_t *bbtp, *buf = chip->nc_page_cache;
1222b6ee221Sahoka size_t left, bbt_pages, i;
1232b6ee221Sahoka
1242b6ee221Sahoka bbt_pages = bbt->nbbt_size / chip->nc_page_size;
1252b6ee221Sahoka if (bbt->nbbt_size % chip->nc_page_size)
1262b6ee221Sahoka bbt_pages++;
1272b6ee221Sahoka
1282b6ee221Sahoka if (nand_isbad(self, addr)) {
1292b6ee221Sahoka return false;
1302b6ee221Sahoka }
1312b6ee221Sahoka
1322b6ee221Sahoka if (nand_bbt_page_has_bbt(self, addr)) {
1332b6ee221Sahoka bbtp = bbt->nbbt_bitmap;
1342b6ee221Sahoka left = bbt->nbbt_size;
1352b6ee221Sahoka
1362b6ee221Sahoka for (i = 0; i < bbt_pages; i++) {
1372b6ee221Sahoka nand_read_page(self, addr, buf);
1382b6ee221Sahoka
1392b6ee221Sahoka if (i == bbt_pages - 1) {
1402b6ee221Sahoka KASSERT(left <= chip->nc_page_size);
1412b6ee221Sahoka memcpy(bbtp, buf, left);
1422b6ee221Sahoka } else {
1432b6ee221Sahoka memcpy(bbtp, buf, chip->nc_page_size);
1442b6ee221Sahoka }
1452b6ee221Sahoka
1462b6ee221Sahoka bbtp += chip->nc_page_size;
1472b6ee221Sahoka left -= chip->nc_page_size;
1482b6ee221Sahoka addr += chip->nc_page_size;
1492b6ee221Sahoka }
1502b6ee221Sahoka
1512b6ee221Sahoka return true;
1522b6ee221Sahoka } else {
1532b6ee221Sahoka return false;
1542b6ee221Sahoka }
1552b6ee221Sahoka }
1562b6ee221Sahoka
1572b6ee221Sahoka bool
nand_bbt_load(device_t self)1582b6ee221Sahoka nand_bbt_load(device_t self)
1592b6ee221Sahoka {
1602b6ee221Sahoka struct nand_softc *sc = device_private(self);
1612b6ee221Sahoka struct nand_chip *chip = &sc->sc_chip;
1626adb739dSahoka flash_off_t blockaddr;
1632b6ee221Sahoka int n;
1642b6ee221Sahoka
1652b6ee221Sahoka blockaddr = chip->nc_size - chip->nc_block_size;
1662b6ee221Sahoka /* XXX currently we check the last 4 blocks */
1672b6ee221Sahoka for (n = 0; n < 4; n++) {
1682b6ee221Sahoka if (nand_bbt_get_bbt_from_page(self, blockaddr)) {
1692b6ee221Sahoka break;
1702b6ee221Sahoka } else {
1712b6ee221Sahoka blockaddr -= chip->nc_block_size;
1722b6ee221Sahoka }
1732b6ee221Sahoka }
1742b6ee221Sahoka
1752b6ee221Sahoka return true;
1762b6ee221Sahoka }
1772b6ee221Sahoka
1782b6ee221Sahoka void
nand_bbt_block_markbad(device_t self,flash_off_t block)1796adb739dSahoka nand_bbt_block_markbad(device_t self, flash_off_t block)
1802b6ee221Sahoka {
1812b6ee221Sahoka if (nand_bbt_block_isbad(self, block)) {
1822b6ee221Sahoka aprint_error_dev(self,
1832b6ee221Sahoka "trying to mark block bad already marked in bbt\n");
1842b6ee221Sahoka }
1852b6ee221Sahoka /* XXX check if this is the correct marker */
1862b6ee221Sahoka nand_bbt_block_mark(self, block, NAND_BBT_MARKER_WORNOUT_BAD);
1872b6ee221Sahoka }
1882b6ee221Sahoka
1892b6ee221Sahoka void
nand_bbt_block_markfactorybad(device_t self,flash_off_t block)1906adb739dSahoka nand_bbt_block_markfactorybad(device_t self, flash_off_t block)
1912b6ee221Sahoka {
1922b6ee221Sahoka if (nand_bbt_block_isbad(self, block)) {
1932b6ee221Sahoka aprint_error_dev(self,
1942b6ee221Sahoka "trying to mark block factory bad already"
1952b6ee221Sahoka " marked in bbt\n");
1962b6ee221Sahoka }
1972b6ee221Sahoka nand_bbt_block_mark(self, block, NAND_BBT_MARKER_FACTORY_BAD);
1982b6ee221Sahoka }
1992b6ee221Sahoka
2002b6ee221Sahoka void
nand_bbt_block_mark(device_t self,flash_off_t block,uint8_t marker)2016adb739dSahoka nand_bbt_block_mark(device_t self, flash_off_t block, uint8_t marker)
2022b6ee221Sahoka {
2032b6ee221Sahoka struct nand_softc *sc = device_private(self);
204570be5cdShtodd struct nand_chip *chip = &sc->sc_chip;
2052b6ee221Sahoka struct nand_bbt *bbt = &sc->sc_bbt;
2062b6ee221Sahoka uint8_t clean;
2072b6ee221Sahoka
208570be5cdShtodd __USE(chip);
2092b6ee221Sahoka KASSERT(block < chip->nc_size / chip->nc_block_size);
2102b6ee221Sahoka
211*df8b6b33Smrg clean = (0xfc << ((block % 4) * 2));
2122b6ee221Sahoka marker = (marker << ((block % 4) * 2));
2132b6ee221Sahoka
2142b6ee221Sahoka /* set byte containing the 2 bit marker for this block */
2152b6ee221Sahoka bbt->nbbt_bitmap[block / 4] &= clean;
2162b6ee221Sahoka bbt->nbbt_bitmap[block / 4] |= marker;
2172b6ee221Sahoka }
2182b6ee221Sahoka
2192b6ee221Sahoka bool
nand_bbt_block_isbad(device_t self,flash_off_t block)2206adb739dSahoka nand_bbt_block_isbad(device_t self, flash_off_t block)
2212b6ee221Sahoka {
2222b6ee221Sahoka struct nand_softc *sc = device_private(self);
223570be5cdShtodd struct nand_chip *chip = &sc->sc_chip;
2242b6ee221Sahoka struct nand_bbt *bbt = &sc->sc_bbt;
2252b6ee221Sahoka uint8_t byte, marker;
2262b6ee221Sahoka bool result;
2272b6ee221Sahoka
228570be5cdShtodd __USE(chip);
2292b6ee221Sahoka KASSERT(block < chip->nc_size / chip->nc_block_size);
2302b6ee221Sahoka
2312b6ee221Sahoka /* get byte containing the 2 bit marker for this block */
2322b6ee221Sahoka byte = bbt->nbbt_bitmap[block / 4];
2332b6ee221Sahoka
2342b6ee221Sahoka /* extract the 2 bit marker from the byte */
2352b6ee221Sahoka marker = (byte >> ((block % 4) * 2)) & 0x03;
2362b6ee221Sahoka
2372b6ee221Sahoka switch (marker) {
2382b6ee221Sahoka case NAND_BBT_MARKER_FACTORY_BAD:
2392b6ee221Sahoka case NAND_BBT_MARKER_WORNOUT_BAD:
2402b6ee221Sahoka case NAND_BBT_MARKER_RESERVED:
2412b6ee221Sahoka result = true;
2422b6ee221Sahoka break;
2432b6ee221Sahoka case NAND_BBT_MARKER_GOOD:
2442b6ee221Sahoka result = false;
2452b6ee221Sahoka break;
2462b6ee221Sahoka default:
2472b6ee221Sahoka panic("error in marker extraction");
2482b6ee221Sahoka }
2492b6ee221Sahoka
2502b6ee221Sahoka return result;
2512b6ee221Sahoka }
252