^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) * inftlmount.c -- INFTL 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: Greg Ungerer (gerg@snapgear.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright © 2002-2003, Greg Ungerer (gerg@snapgear.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Based heavily on the nftlmount.c code which is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright © 2000 Netgem S.A.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/mtd/nftl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/mtd/inftl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * find_boot_record: Find the INFTL Media Header and its Spare copy which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * contains the various device information of the INFTL partition and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * Bad Unit Table. Update the PUtable[] table according to the Bad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * Unit Table. PUtable[] is used for management of Erase Unit in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * other routines in inftlcore.c and inftlmount.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int find_boot_record(struct INFTLrecord *inftl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct inftl_unittail h1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) //struct inftl_oob oob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned int i, block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u8 buf[SECTORSIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct INFTLMediaHeader *mh = &inftl->MediaHdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct mtd_info *mtd = inftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct INFTLPartition *ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) pr_debug("INFTL: find_boot_record(inftl=%p)\n", inftl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * Assume logical EraseSize == physical erasesize for starting the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * scan. We'll sort it out later if we find a MediaHeader which says
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) inftl->EraseSize = inftl->mbd.mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) inftl->MediaUnit = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* Search for a valid boot record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) for (block = 0; block < inftl->nb_blocks; block++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * Check for BNAND header first. Then whinge if it's found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * but later checks fail.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ret = mtd_read(mtd, block * inftl->EraseSize, SECTORSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* We ignore ret in case the ECC of the MediaHeader is invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) (which is apparently acceptable) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (retlen != SECTORSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int warncount = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (warncount) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) printk(KERN_WARNING "INFTL: block read at 0x%x "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) "of mtd%d failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) block * inftl->EraseSize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) inftl->mbd.mtd->index, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (!--warncount)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) printk(KERN_WARNING "INFTL: further "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) "failures for this block will "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) "not be printed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (retlen < 6 || memcmp(buf, "BNAND", 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* BNAND\0 not found. Continue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* To be safer with BIOS, also use erase mark as discriminant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ret = inftl_read_oob(mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) block * inftl->EraseSize + SECTORSIZE + 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) 8, &retlen,(char *)&h1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) printk(KERN_WARNING "INFTL: ANAND header found at "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) "0x%x in mtd%d, but OOB data read failed "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) "(err %d)\n", block * inftl->EraseSize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) inftl->mbd.mtd->index, ret);
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * This is the first we've seen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * Copy the media header structure into place.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* Read the spare media header at offset 4096 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) mtd_read(mtd, block * inftl->EraseSize + 4096, SECTORSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (retlen != SECTORSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) printk(KERN_WARNING "INFTL: Unable to read spare "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) "Media Header\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* Check if this one is the same as the first one we found. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) printk(KERN_WARNING "INFTL: Primary and spare Media "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) "Headers disagree.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) pr_debug("INFTL: Media Header ->\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) " bootRecordID = %s\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) " NoOfBootImageBlocks = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) " NoOfBinaryPartitions = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) " NoOfBDTLPartitions = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) " BlockMultiplierBits = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) " FormatFlgs = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) " OsakVersion = 0x%x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) " PercentUsed = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) mh->bootRecordID, mh->NoOfBootImageBlocks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) mh->NoOfBinaryPartitions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) mh->NoOfBDTLPartitions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) mh->BlockMultiplierBits, mh->FormatFlags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) mh->OsakVersion, mh->PercentUsed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (mh->NoOfBDTLPartitions == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) printk(KERN_WARNING "INFTL: Media Header sanity check "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) "failed: NoOfBDTLPartitions (%d) == 0, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) "must be at least 1\n", mh->NoOfBDTLPartitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) printk(KERN_WARNING "INFTL: Media Header sanity check "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) "failed: Total Partitions (%d) > 4, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) "BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) mh->NoOfBinaryPartitions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) mh->NoOfBDTLPartitions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) mh->NoOfBinaryPartitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (mh->BlockMultiplierBits > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) printk(KERN_WARNING "INFTL: sorry, we don't support "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) "UnitSizeFactor 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) mh->BlockMultiplierBits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) } else if (mh->BlockMultiplierBits == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) printk(KERN_WARNING "INFTL: support for INFTL with "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) "UnitSizeFactor 0x%02x is experimental\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) mh->BlockMultiplierBits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) inftl->EraseSize = inftl->mbd.mtd->erasesize <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) mh->BlockMultiplierBits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) block >>= mh->BlockMultiplierBits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* Scan the partitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) for (i = 0; (i < 4); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) ip = &mh->Partitions[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) ip->virtualUnits = le32_to_cpu(ip->virtualUnits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) ip->firstUnit = le32_to_cpu(ip->firstUnit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ip->lastUnit = le32_to_cpu(ip->lastUnit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ip->flags = le32_to_cpu(ip->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) ip->spareUnits = le32_to_cpu(ip->spareUnits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) ip->Reserved0 = le32_to_cpu(ip->Reserved0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) pr_debug(" PARTITION[%d] ->\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) " virtualUnits = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) " firstUnit = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) " lastUnit = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) " flags = 0x%x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) " spareUnits = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) i, ip->virtualUnits, ip->firstUnit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ip->lastUnit, ip->flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ip->spareUnits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (ip->Reserved0 != ip->firstUnit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct erase_info *instr = &inftl->instr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * Most likely this is using the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * undocumented qiuck mount feature.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * We don't support that, we will need
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * to erase the hidden block for full
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * compatibility.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) instr->addr = ip->Reserved0 * inftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) instr->len = inftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) mtd_erase(mtd, instr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) printk(KERN_WARNING "INFTL: Media Header "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) "Partition %d sanity check failed\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) " firstUnit %d : lastUnit %d > "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) "virtualUnits %d\n", i, ip->lastUnit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) ip->firstUnit, ip->Reserved0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (ip->Reserved1 != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) printk(KERN_WARNING "INFTL: Media Header "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) "Partition %d sanity check failed: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) "Reserved1 %d != 0\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) i, ip->Reserved1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (ip->flags & INFTL_BDTL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (i >= 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) printk(KERN_WARNING "INFTL: Media Header Partition "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) "sanity check failed:\n No partition "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) "marked as Disk Partition\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) inftl->nb_boot_blocks = ip->firstUnit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) inftl->numvunits = ip->virtualUnits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (inftl->numvunits > (inftl->nb_blocks -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) inftl->nb_boot_blocks - 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) printk(KERN_WARNING "INFTL: Media Header sanity check "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) "failed:\n numvunits (%d) > nb_blocks "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) "(%d) - nb_boot_blocks(%d) - 2\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) inftl->numvunits, inftl->nb_blocks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) inftl->nb_boot_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) inftl->mbd.size = inftl->numvunits *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) (inftl->EraseSize / SECTORSIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * Block count is set to last used EUN (we won't need to keep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * any meta-data past that point).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) inftl->firstEUN = ip->firstUnit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) inftl->lastEUN = ip->lastUnit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) inftl->nb_blocks = ip->lastUnit + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* Memory alloc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) inftl->PUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (!inftl->PUtable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) printk(KERN_WARNING "INFTL: allocation of PUtable "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) "failed (%zd bytes)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) inftl->nb_blocks * sizeof(u16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) inftl->VUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (!inftl->VUtable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) kfree(inftl->PUtable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) printk(KERN_WARNING "INFTL: allocation of VUtable "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) "failed (%zd bytes)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) inftl->nb_blocks * sizeof(u16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* Mark the blocks before INFTL MediaHeader as reserved */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) for (i = 0; i < inftl->nb_boot_blocks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) inftl->PUtable[i] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* Mark all remaining blocks as potentially containing data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) for (; i < inftl->nb_blocks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) inftl->PUtable[i] = BLOCK_NOTEXPLORED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) /* Mark this boot record (NFTL MediaHeader) block as reserved */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) inftl->PUtable[block] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* Read Bad Erase Unit Table and modify PUtable[] accordingly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) for (i = 0; i < inftl->nb_blocks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int physblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* If any of the physical eraseblocks are bad, don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) use the unit. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (mtd_block_isbad(inftl->mbd.mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) i * inftl->EraseSize + physblock))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) inftl->PUtable[i] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) inftl->MediaUnit = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /* Not found. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static int memcmpb(void *a, int c, int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) for (i = 0; i < n; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (c != ((unsigned char *)a)[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * check_free_sector: check if a free sector is actually FREE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) * i.e. All 0xff in data and oob area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) int len, int check_oob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) struct mtd_info *mtd = inftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) u8 *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) for (i = 0; i < len; i += SECTORSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (check_oob) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if(inftl_read_oob(mtd, address, mtd->oobsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) &retlen, &buf[SECTORSIZE]) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) address += SECTORSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * Unit and Update INFTL metadata. Each erase operation is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * checked with check_free_sectors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * Return: 0 when succeed, -1 on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * ToDo: 1. Is it necessary to check_free_sector after erasing ??
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) int INFTL_formatblock(struct INFTLrecord *inftl, int block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct inftl_unittail uci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) struct erase_info *instr = &inftl->instr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) struct mtd_info *mtd = inftl->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) int physblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) memset(instr, 0, sizeof(struct erase_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) /* FIXME: Shouldn't we be setting the 'discarded' flag to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) _first_? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /* Use async erase interface, test return code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) instr->addr = block * inftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) instr->len = inftl->mbd.mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /* Erase one physical eraseblock at a time, even though the NAND api
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) allows us to group them. This way we if we have a failure, we can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) mark only the failed block in the bbt. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) for (physblock = 0; physblock < inftl->EraseSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) physblock += instr->len, instr->addr += instr->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) ret = mtd_erase(inftl->mbd.mtd, instr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) printk(KERN_WARNING "INFTL: error while formatting block %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * Check the "freeness" of Erase Unit before updating metadata.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) * FixMe: is this check really necessary? Since we have check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * the return code after the erase operation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) uci.EraseMark = cpu_to_le16(ERASE_MARK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) uci.Reserved[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) uci.Reserved[1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) uci.Reserved[2] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) uci.Reserved[3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (inftl_write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) /* could not format, update the bad block table (caller is responsible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) for setting the PUtable to BLOCK_RESERVED on failure) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) mtd_block_markbad(inftl->mbd.mtd, instr->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * format_chain: Format an invalid Virtual Unit chain. It frees all the Erase
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * Units in a Virtual Unit Chain, i.e. all the units are disconnected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * Since the chain is invalid then we will have to erase it from its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * head (normally for INFTL we go from the oldest). But if it has a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * loop then there is no oldest...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) static void format_chain(struct INFTLrecord *inftl, unsigned int first_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) unsigned int block = first_block, block1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) printk(KERN_WARNING "INFTL: formatting chain at block %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) block1 = inftl->PUtable[block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) printk(KERN_WARNING "INFTL: formatting block %d\n", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (INFTL_formatblock(inftl, block) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * Cannot format !!!! Mark it as Bad Unit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) inftl->PUtable[block] = BLOCK_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) inftl->PUtable[block] = BLOCK_FREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) /* Goto next block on the chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) block = block1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (block == BLOCK_NIL || block >= inftl->lastEUN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) void INFTL_dumptables(struct INFTLrecord *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) pr_debug("-------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) "----------------------------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) pr_debug("VUtable[%d] ->", s->nb_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) for (i = 0; i < s->nb_blocks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if ((i % 8) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) pr_debug("\n%04x: ", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pr_debug("%04x ", s->VUtable[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) pr_debug("\n-------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) "----------------------------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) for (i = 0; i <= s->lastEUN; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if ((i % 8) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) pr_debug("\n%04x: ", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) pr_debug("%04x ", s->PUtable[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) pr_debug("\n-------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) "----------------------------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) pr_debug("INFTL ->\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) " EraseSize = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) " h/s/c = %d/%d/%d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) " numvunits = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) " firstEUN = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) " lastEUN = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) " numfreeEUNs = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) " LastFreeEUN = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) " nb_blocks = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) " nb_boot_blocks = %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) s->EraseSize, s->heads, s->sectors, s->cylinders,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) pr_debug("\n-------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) "----------------------------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) void INFTL_dumpVUchains(struct INFTLrecord *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) int logical, block, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) pr_debug("-------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) "----------------------------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) pr_debug("INFTL Virtual Unit Chains:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) for (logical = 0; logical < s->nb_blocks; logical++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) block = s->VUtable[logical];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (block >= s->nb_blocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) pr_debug(" LOGICAL %d --> %d ", logical, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) for (i = 0; i < s->nb_blocks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (s->PUtable[block] == BLOCK_NIL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) block = s->PUtable[block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) pr_debug("%d ", block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) pr_debug("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) pr_debug("-------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) "----------------------------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) int INFTL_mount(struct INFTLrecord *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) struct mtd_info *mtd = s->mbd.mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) unsigned int block, first_block, prev_block, last_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) unsigned int first_logical_block, logical_block, erase_mark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) int chain_length, do_format_chain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) struct inftl_unithead1 h0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct inftl_unittail h1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) u8 *ANACtable, ANAC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) pr_debug("INFTL: INFTL_mount(inftl=%p)\n", s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) /* Search for INFTL MediaHeader and Spare INFTL Media Header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (find_boot_record(s) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) printk(KERN_WARNING "INFTL: could not find valid boot record?\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /* Init the logical to physical table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) for (i = 0; i < s->nb_blocks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) s->VUtable[i] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) logical_block = block = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /* Temporary buffer to store ANAC numbers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) if (!ANACtable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) printk(KERN_WARNING "INFTL: allocation of ANACtable "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) "failed (%zd bytes)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) s->nb_blocks * sizeof(u8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * First pass is to explore each physical unit, and construct the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * virtual chains that exist (newest physical unit goes into VUtable).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * Any block that is in any way invalid will be left in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * NOTEXPLORED state. Then at the end we will try to format it and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) * mark it as free.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) pr_debug("INFTL: pass 1, explore each unit\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (s->PUtable[first_block] != BLOCK_NOTEXPLORED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) do_format_chain = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) first_logical_block = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) last_block = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) block = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) for (chain_length = 0; ; chain_length++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if ((chain_length == 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) (s->PUtable[block] != BLOCK_NOTEXPLORED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) /* Nothing to do here, onto next block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (inftl_read_oob(mtd, block * s->EraseSize + 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 8, &retlen, (char *)&h0) < 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) inftl_read_oob(mtd, block * s->EraseSize +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 2 * SECTORSIZE + 8, 8, &retlen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) (char *)&h1) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) /* Should never happen? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) do_format_chain++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) logical_block = le16_to_cpu(h0.virtualUnitNo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) prev_block = le16_to_cpu(h0.prevUnitNo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) ANACtable[block] = h0.ANAC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) /* Previous block is relative to start of Partition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (prev_block < s->nb_blocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) prev_block += s->firstEUN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /* Already explored partial chain? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (s->PUtable[block] != BLOCK_NOTEXPLORED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) /* Check if chain for this logical */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (logical_block == first_logical_block) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (last_block != BLOCK_NIL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) s->PUtable[last_block] = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) /* Check for invalid block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) if (erase_mark != ERASE_MARK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) printk(KERN_WARNING "INFTL: corrupt block %d "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) "in chain %d, chain length %d, erase "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) "mark 0x%x?\n", block, first_block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) chain_length, erase_mark);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * Assume end of chain, probably incomplete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * fold/erase...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (chain_length == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) do_format_chain++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* Check for it being free already then... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if ((logical_block == BLOCK_FREE) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) (logical_block == BLOCK_NIL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) s->PUtable[block] = BLOCK_FREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) /* Sanity checks on block numbers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if ((logical_block >= s->nb_blocks) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) ((prev_block >= s->nb_blocks) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) (prev_block != BLOCK_NIL))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (chain_length > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) printk(KERN_WARNING "INFTL: corrupt "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) "block %d in chain %d?\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) block, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) do_format_chain++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (first_logical_block == BLOCK_NIL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) first_logical_block = logical_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (first_logical_block != logical_block) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) /* Normal for folded chain... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * Current block is valid, so if we followed a virtual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * chain to get here then we can set the previous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * block pointer in our PUtable now. Then move onto
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * the previous block in the chain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) s->PUtable[block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (last_block != BLOCK_NIL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) s->PUtable[last_block] = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) last_block = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) block = prev_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) /* Check for end of chain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) if (block == BLOCK_NIL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) /* Validate next block before following it... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) if (block > s->lastEUN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) printk(KERN_WARNING "INFTL: invalid previous "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) "block %d in chain %d?\n", block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) do_format_chain++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) if (do_format_chain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) format_chain(s, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) * Looks like a valid chain then. It may not really be the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) * newest block in the chain, but it is the newest we have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) * found so far. We might update it in later iterations of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) * this loop if we find something newer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) s->VUtable[first_logical_block] = first_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) logical_block = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) INFTL_dumptables(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) * Second pass, check for infinite loops in chains. These are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) * possible because we don't update the previous pointers when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) * we fold chains. No big deal, just fix them up in PUtable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) pr_debug("INFTL: pass 2, validate virtual chains\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) for (logical_block = 0; logical_block < s->numvunits; logical_block++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) block = s->VUtable[logical_block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) last_block = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) /* Check for free/reserved/nil */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) if (block >= BLOCK_RESERVED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) ANAC = ANACtable[block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) for (i = 0; i < s->numvunits; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (s->PUtable[block] == BLOCK_NIL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) if (s->PUtable[block] > s->lastEUN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) printk(KERN_WARNING "INFTL: invalid prev %d, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) "in virtual chain %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) s->PUtable[block], logical_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) s->PUtable[block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (ANACtable[block] != ANAC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) * Chain must point back to itself. This is ok,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) * but we will need adjust the tables with this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) * newest block and oldest block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) s->VUtable[logical_block] = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) s->PUtable[last_block] = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) ANAC--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) last_block = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) block = s->PUtable[block];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) if (i >= s->nb_blocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) * Uhoo, infinite chain with valid ANACS!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) * Format whole chain...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) format_chain(s, first_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) INFTL_dumptables(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) INFTL_dumpVUchains(s);
^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) * Third pass, format unreferenced blocks and init free block count.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) s->numfreeEUNs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) s->LastFreeEUN = BLOCK_NIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) pr_debug("INFTL: pass 3, format unused blocks\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) for (block = s->firstEUN; block <= s->lastEUN; block++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (s->PUtable[block] == BLOCK_NOTEXPLORED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) printk("INFTL: unreferenced block %d, formatting it\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (INFTL_formatblock(s, block) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) s->PUtable[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->PUtable[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->PUtable[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) if (s->LastFreeEUN == BLOCK_NIL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) s->LastFreeEUN = block;
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) kfree(ANACtable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) }