^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * NFTL mount code with extensive checks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright © 2000 Netgem S.A.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mtd/rawnand.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mtd/nftl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define SECTORSIZE 512
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * various device information of the NFTL partition and Bad Unit Table. Update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * the ReplUnitTable[] table according to the Bad Unit Table. ReplUnitTable[]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * is used for management of Erase Unit in other routines in nftl.c and nftlmount.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static int find_boot_record(struct NFTLrecord *nftl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct nftl_uci1 h1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned int block, boot_record_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u8 buf[SECTORSIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct NFTLMediaHeader *mh = &nftl->MediaHdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct mtd_info *mtd = nftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Assume logical EraseSize == physical erasesize for starting the scan.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) We'll sort it out later if we find a MediaHeader which says otherwise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* Actually, we won't. The new DiskOnChip driver has already scanned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) the MediaHeader and adjusted the virtual erasesize it presents in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) the mtd device accordingly. We could even get rid of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) nftl->EraseSize if there were any point in doing so. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) nftl->EraseSize = nftl->mbd.mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) nftl->MediaUnit = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) nftl->SpareMediaUnit = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* search for a valid boot record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) for (block = 0; block < nftl->nb_blocks; block++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* Check for ANAND header first. Then can whinge if it's found but later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) checks fail */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) ret = mtd_read(mtd, block * nftl->EraseSize, SECTORSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* We ignore ret in case the ECC of the MediaHeader is invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) (which is apparently acceptable) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (retlen != SECTORSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int warncount = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (warncount) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (!--warncount)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) printk(KERN_WARNING "Further failures for this block will not be printed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* ANAND\0 not found. Continue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) block * nftl->EraseSize, nftl->mbd.mtd->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* To be safer with BIOS, also use erase mark as discriminant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = nftl_read_oob(mtd, block * nftl->EraseSize +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) SECTORSIZE + 8, 8, &retlen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) (char *)&h1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #if 0 /* Some people seem to have devices without ECC or erase marks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) on the Media Header blocks. There are enough other sanity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) checks in here that we can probably do without it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) block * nftl->EraseSize, nftl->mbd.mtd->index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* Finally reread to check ECC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* Paranoia. Check the ANAND header is still there after the ECC read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (memcmp(buf, "ANAND", 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) block * nftl->EraseSize, nftl->mbd.mtd->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) printk(KERN_NOTICE "New data are: %6ph\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* OK, we like it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (boot_record_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* We've already processed one. So we just check if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) this one is the same as the first one we found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* if (debug) Print both side by side */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (boot_record_count < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /* We haven't yet seen two real ones */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (boot_record_count == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) nftl->SpareMediaUnit = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Mark this boot record (NFTL MediaHeader) block as reserved */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) nftl->ReplUnitTable[block] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) boot_record_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* This is the first we've seen. Copy the media header structure into place */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* Do some sanity checks on it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) The new DiskOnChip driver scans the MediaHeader itself, and presents a virtual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) erasesize based on UnitSizeFactor. So the erasesize we read from the mtd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) device is already correct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (mh->UnitSizeFactor == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) } else if (mh->UnitSizeFactor < 0xfc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) } else if (mh->UnitSizeFactor != 0xff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) nftl->nb_boot_blocks, nftl->nb_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) printk(KERN_NOTICE "numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* If we're not using the last sectors in the device for some reason,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) reduce nb_blocks accordingly so we forget they're there */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /* XXX: will be suppressed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) nftl->lastEUN = nftl->nb_blocks - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* memory alloc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) nftl->EUNtable = kmalloc_array(nftl->nb_blocks, sizeof(u16),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!nftl->EUNtable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) nftl->ReplUnitTable = kmalloc_array(nftl->nb_blocks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) sizeof(u16),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (!nftl->ReplUnitTable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) kfree(nftl->EUNtable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) for (i = 0; i < nftl->nb_boot_blocks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) nftl->ReplUnitTable[i] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* mark all remaining blocks as potentially containing data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) for (; i < nftl->nb_blocks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* Mark this boot record (NFTL MediaHeader) block as reserved */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) nftl->ReplUnitTable[block] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) for (i = 0; i < nftl->nb_blocks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) The new DiskOnChip driver already scanned the bad block table. Just query it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if ((i & (SECTORSIZE - 1)) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /* read one sector for every SECTORSIZE of blocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) ret = mtd->read(nftl->mbd.mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) block * nftl->EraseSize + i +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) SECTORSIZE, SECTORSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) kfree(nftl->ReplUnitTable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) kfree(nftl->EUNtable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (buf[i & (SECTORSIZE - 1)] != 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) nftl->ReplUnitTable[i] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (mtd_block_isbad(nftl->mbd.mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) i * nftl->EraseSize))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) nftl->ReplUnitTable[i] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) nftl->MediaUnit = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) boot_record_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) } /* foreach (block) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return boot_record_count?0:-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static int memcmpb(void *a, int c, int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) for (i = 0; i < n; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (c != ((unsigned char *)a)[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int check_oob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct mtd_info *mtd = nftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) u8 *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) for (i = 0; i < len; i += SECTORSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (check_oob) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if(nftl_read_oob(mtd, address, mtd->oobsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) &retlen, &buf[SECTORSIZE]) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) address += SECTORSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /* NFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase Unit and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * Update NFTL metadata. Each erase operation is checked with check_free_sectors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * Return: 0 when succeed, -1 on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * ToDo: 1. Is it necessary to check_free_sector after erasing ??
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) int NFTL_formatblock(struct NFTLrecord *nftl, int block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) unsigned int nb_erases, erase_mark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) struct nftl_uci1 uci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct erase_info *instr = &nftl->instr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct mtd_info *mtd = nftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /* Read the Unit Control Information #1 for Wear-Leveling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 8, &retlen, (char *)&uci) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) goto default_uci1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (erase_mark != ERASE_MARK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) default_uci1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) uci.EraseMark = cpu_to_le16(ERASE_MARK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) uci.WearInfo = cpu_to_le32(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) memset(instr, 0, sizeof(struct erase_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /* XXX: use async erase interface, XXX: test return code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) instr->addr = block * nftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) instr->len = nftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (mtd_erase(mtd, instr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) printk("Error while formatting block %d\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /* increase and write Wear-Leveling info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) nb_erases = le32_to_cpu(uci.WearInfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) nb_erases++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /* wrap (almost impossible with current flash) or free block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (nb_erases == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) nb_erases = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /* check the "freeness" of Erase Unit before updating metadata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) * FixMe: is this check really necessary ? since we have check the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * return code after the erase operation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) uci.WearInfo = le32_to_cpu(nb_erases);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (nftl_write_oob(mtd, block * nftl->EraseSize + SECTORSIZE +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 8, 8, &retlen, (char *)&uci) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* could not format, update the bad block table (caller is responsible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) for setting the ReplUnitTable to BLOCK_RESERVED on failure) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) mtd_block_markbad(nftl->mbd.mtd, instr->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) /* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * Mark as 'IGNORE' each incorrect sector. This check is only done if the chain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * was being folded when NFTL was interrupted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * The check_free_sectors in this function is necessary. There is a possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * situation that after writing the Data area, the Block Control Information is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * not updated according (due to power failure or something) which leaves the block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * in an inconsistent state. So we have to check if a block is really FREE in this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * case. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) struct mtd_info *mtd = nftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) unsigned int block, i, status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) struct nftl_bci bci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) int sectors_per_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) sectors_per_block = nftl->EraseSize / SECTORSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) block = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) for (i = 0; i < sectors_per_block; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (nftl_read_oob(mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) block * nftl->EraseSize + i * SECTORSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 8, &retlen, (char *)&bci) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) status = SECTOR_IGNORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) status = bci.Status | bci.Status1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) switch(status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) case SECTOR_FREE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) /* verify that the sector is really free. If not, mark
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) as ignore */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (memcmpb(&bci, 0xff, 8) != 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) SECTORSIZE, 0) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) printk("Incorrect free sector %d in block %d: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) "marking it as ignored\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) i, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* sector not free actually : mark it as SECTOR_IGNORE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) bci.Status = SECTOR_IGNORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) bci.Status1 = SECTOR_IGNORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) nftl_write_oob(mtd, block *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) nftl->EraseSize +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) i * SECTORSIZE, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) &retlen, (char *)&bci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) /* proceed to next Erase Unit on the chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) block = nftl->ReplUnitTable[block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) printk("incorrect ReplUnitTable[] : %d\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (block == BLOCK_NIL || block >= nftl->nb_blocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /* calc_chain_length: Walk through a Virtual Unit Chain and estimate chain length */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) unsigned int length = 0, block = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) length++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* avoid infinite loops, although this is guaranteed not to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) happen because of the previous checks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (length >= nftl->nb_blocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) printk("nftl: length too long %d !\n", length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) block = nftl->ReplUnitTable[block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) printk("incorrect ReplUnitTable[] : %d\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (block == BLOCK_NIL || block >= nftl->nb_blocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) /* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * Virtual Unit Chain, i.e. all the units are disconnected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * It is not strictly correct to begin from the first block of the chain because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * if we stop the code, we may see again a valid chain if there was a first_block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * flag in a block inside it. But is it really a problem ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) * FixMe: Figure out what the last statement means. What if power failure when we are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * in the for (;;) loop formatting blocks ??
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) unsigned int block = first_block, block1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) printk("Formatting chain at block %d\n", first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) block1 = nftl->ReplUnitTable[block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) printk("Formatting block %d\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (NFTL_formatblock(nftl, block) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) /* cannot format !!!! Mark it as Bad Unit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) nftl->ReplUnitTable[block] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) nftl->ReplUnitTable[block] = BLOCK_FREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) /* goto next block on the chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) block = block1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) printk("incorrect ReplUnitTable[] : %d\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (block == BLOCK_NIL || block >= nftl->nb_blocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) /* check_and_mark_free_block: Verify that a block is free in the NFTL sense (valid erase mark) or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) * totally free (only 0xff).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) * following criteria:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) * 1. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) struct mtd_info *mtd = nftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) struct nftl_uci1 h1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) unsigned int erase_mark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /* check erase mark. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) &retlen, (char *)&h1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (erase_mark != ERASE_MARK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* if no erase mark, the block must be totally free. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) possible in two cases : empty filesystem or interrupted erase (very unlikely) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /* free block : write erase mark */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) h1.EraseMark = cpu_to_le16(ERASE_MARK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) h1.WearInfo = cpu_to_le32(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (nftl_write_oob(mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) block * nftl->EraseSize + SECTORSIZE + 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) &retlen, (char *)&h1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) /* if erase mark present, need to skip it when doing check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) for (i = 0; i < nftl->EraseSize; i += SECTORSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* check free sector */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (check_free_sectors (nftl, block * nftl->EraseSize + i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) SECTORSIZE, 0) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (nftl_read_oob(mtd, block * nftl->EraseSize + i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 16, &retlen, buf) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (i == SECTORSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) /* skip erase mark */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (memcmpb(buf, 0xff, 8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (memcmpb(buf, 0xff, 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) /* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) * to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) * is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) * for some reason. A clean up/check of the VUC is necessary in this case.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * WARNING: return 0 if read error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) struct mtd_info *mtd = nftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) struct nftl_uci2 uci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (nftl_read_oob(mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 8, &retlen, (char *)&uci) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) return le16_to_cpu((uci.FoldMark | uci.FoldMark1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) int NFTL_mount(struct NFTLrecord *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) unsigned int first_logical_block, logical_block, rep_block, erase_mark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) unsigned int block, first_block, is_first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) int chain_length, do_format_chain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct nftl_uci0 h0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct nftl_uci1 h1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) struct mtd_info *mtd = s->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) /* search for NFTL MediaHeader and Spare NFTL Media Header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (find_boot_record(s) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) printk("Could not find valid boot record\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /* init the logical to physical table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) for (i = 0; i < s->nb_blocks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) s->EUNtable[i] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /* first pass : explore each block chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) first_logical_block = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) for (first_block = 0; first_block < s->nb_blocks; first_block++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) /* if the block was not already explored, we can look at it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (s->ReplUnitTable[first_block] == BLOCK_NOTEXPLORED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) block = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) chain_length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) do_format_chain = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) /* read the block header. If error, we format the chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (nftl_read_oob(mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) block * s->EraseSize + 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) &retlen, (char *)&h0) < 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) nftl_read_oob(mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) block * s->EraseSize +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) SECTORSIZE + 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) &retlen, (char *)&h1) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) s->ReplUnitTable[block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) do_format_chain = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) logical_block = le16_to_cpu ((h0.VirtUnitNum | h0.SpareVirtUnitNum));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) rep_block = le16_to_cpu ((h0.ReplUnitNum | h0.SpareReplUnitNum));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) is_first_block = !(logical_block >> 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) logical_block = logical_block & 0x7fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) /* invalid/free block test */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (erase_mark != ERASE_MARK || logical_block >= s->nb_blocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) if (chain_length == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /* if not currently in a chain, we can handle it safely */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (check_and_mark_free_block(s, block) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) /* not really free: format it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) printk("Formatting block %d\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (NFTL_formatblock(s, block) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) /* could not format: reserve the block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) s->ReplUnitTable[block] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) s->ReplUnitTable[block] = BLOCK_FREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) /* free block: mark it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) s->ReplUnitTable[block] = BLOCK_FREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* directly examine the next block. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) goto examine_ReplUnitTable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* the block was in a chain : this is bad. We
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) must format all the chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) printk("Block %d: free but referenced in chain %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) block, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) s->ReplUnitTable[block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) do_format_chain = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) /* we accept only first blocks here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (chain_length == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) /* this block is not the first block in chain :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) ignore it, it will be included in a chain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) later, or marked as not explored */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (!is_first_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) goto examine_ReplUnitTable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) first_logical_block = logical_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (logical_block != first_logical_block) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) printk("Block %d: incorrect logical block: %d expected: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) block, logical_block, first_logical_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /* the chain is incorrect : we must format it,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) but we need to read it completely */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) do_format_chain = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (is_first_block) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) /* we accept that a block is marked as first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) block while being last block in a chain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) only if the chain is being folded */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (get_fold_mark(s, block) != FOLD_MARK_IN_PROGRESS ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) rep_block != 0xffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) printk("Block %d: incorrectly marked as first block in chain\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) /* the chain is incorrect : we must format it,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) but we need to read it completely */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) do_format_chain = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) printk("Block %d: folding in progress - ignoring first block flag\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) chain_length++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) if (rep_block == 0xffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) /* no more blocks after */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) s->ReplUnitTable[block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) } else if (rep_block >= s->nb_blocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) printk("Block %d: referencing invalid block %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) block, rep_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) do_format_chain = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) s->ReplUnitTable[block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) } else if (s->ReplUnitTable[rep_block] != BLOCK_NOTEXPLORED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) /* same problem as previous 'is_first_block' test:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) we accept that the last block of a chain has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) the first_block flag set if folding is in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) progress. We handle here the case where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) last block appeared first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (s->ReplUnitTable[rep_block] == BLOCK_NIL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) s->EUNtable[first_logical_block] == rep_block &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) get_fold_mark(s, first_block) == FOLD_MARK_IN_PROGRESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) /* EUNtable[] will be set after */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) printk("Block %d: folding in progress - ignoring first block flag\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) rep_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) s->ReplUnitTable[block] = rep_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) s->EUNtable[first_logical_block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) printk("Block %d: referencing block %d already in another chain\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) block, rep_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) /* XXX: should handle correctly fold in progress chains */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) do_format_chain = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) s->ReplUnitTable[block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) /* this is OK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) s->ReplUnitTable[block] = rep_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) block = rep_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) /* the chain was completely explored. Now we can decide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) what to do with it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) if (do_format_chain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) /* invalid chain : format it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) format_chain(s, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) unsigned int first_block1, chain_to_format, chain_length1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) int fold_mark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) /* valid chain : get foldmark */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) fold_mark = get_fold_mark(s, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (fold_mark == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) /* cannot get foldmark : format the chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) printk("Could read foldmark at block %d\n", first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) format_chain(s, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) if (fold_mark == FOLD_MARK_IN_PROGRESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) check_sectors_in_chain(s, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) /* now handle the case where we find two chains at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) same virtual address : we select the longer one,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) because the shorter one is the one which was being
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) folded if the folding was not done in place */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) first_block1 = s->EUNtable[first_logical_block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (first_block1 != BLOCK_NIL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) /* XXX: what to do if same length ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) chain_length1 = calc_chain_length(s, first_block1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) first_block1, chain_length1, first_block, chain_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) if (chain_length >= chain_length1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) chain_to_format = first_block1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) s->EUNtable[first_logical_block] = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) chain_to_format = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) format_chain(s, chain_to_format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) s->EUNtable[first_logical_block] = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) examine_ReplUnitTable:;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) /* second pass to format unreferenced blocks and init free block count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) s->numfreeEUNs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) for (block = 0; block < s->nb_blocks; block++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) printk("Unreferenced block %d, formatting it\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (NFTL_formatblock(s, block) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) s->ReplUnitTable[block] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) s->ReplUnitTable[block] = BLOCK_FREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (s->ReplUnitTable[block] == BLOCK_FREE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) s->numfreeEUNs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) s->LastFreeEUN = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }