The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/nand/nand_bbt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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@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 }

Cache object: 748af621d60ca15381aa2b7b156f8ef5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.