X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmtd%2Finftlmount.c;h=042c4eeadf8ec6100b978a9e1b310fc25702306e;hb=08559aee03be26f1300e0b97f98cf5975095ec7a;hp=64cc97ca7bd310ce0ea2690006dd2bdcd4332298;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 64cc97ca7..042c4eead 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -8,7 +8,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: inftlmount.c,v 1.14 2004/08/09 13:57:42 dwmw2 Exp $ + * $Id: inftlmount.c,v 1.11 2003/06/23 07:39:21 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ #include #include -char inftlmountrev[]="$Revision: 1.14 $"; +char inftlmountrev[]="$Revision: 1.11 $"; /* * find_boot_record: Find the INFTL Media Header and its Spare copy which @@ -54,13 +54,14 @@ static int find_boot_record(struct INFTLrecord *inftl) { struct inftl_unittail h1; //struct inftl_oob oob; - unsigned int i, block; + unsigned int i, block, boot_record_count = 0; u8 buf[SECTORSIZE]; struct INFTLMediaHeader *mh = &inftl->MediaHdr; struct INFTLPartition *ip; - size_t retlen; + int retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=%p)\n", inftl); + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=0x%x)\n", + (int)inftl); /* * Assume logical EraseSize == physical erasesize for starting the @@ -71,6 +72,7 @@ static int find_boot_record(struct INFTLrecord *inftl) inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; inftl->MediaUnit = BLOCK_NIL; + inftl->SpareMediaUnit = BLOCK_NIL; /* Search for a valid boot record */ for (block = 0; block < inftl->nb_blocks; block++) { @@ -80,11 +82,8 @@ static int find_boot_record(struct INFTLrecord *inftl) * Check for BNAND header first. Then whinge if it's found * but later checks fail. */ - ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize, - SECTORSIZE, &retlen, buf); - /* We ignore ret in case the ECC of the MediaHeader is invalid - (which is apparently acceptable) */ - if (retlen != SECTORSIZE) { + if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize, + SECTORSIZE, &retlen, buf))) { static int warncount = 5; if (warncount) { @@ -115,28 +114,36 @@ static int find_boot_record(struct INFTLrecord *inftl) continue; } + if (boot_record_count) { + /* + * We've already processed one. So we just check if + * this one is the same as the first one we found. + */ + if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) { + printk(KERN_WARNING "INFTL: Media Headers at " + "0x%x and 0x%x disagree.\n", + inftl->MediaUnit * inftl->EraseSize, + block * inftl->EraseSize); + return -1; + } + if (boot_record_count == 1) + inftl->SpareMediaUnit = block; + + /* + * Mark this boot record (INFTL MediaHeader) block as + * reserved. + */ + inftl->PUtable[block] = BLOCK_RESERVED; + + boot_record_count++; + continue; + } /* * This is the first we've seen. * Copy the media header structure into place. */ memcpy(mh, buf, sizeof(struct INFTLMediaHeader)); - - /* Read the spare media header at offset 4096 */ - MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize + 4096, - SECTORSIZE, &retlen, buf); - if (retlen != SECTORSIZE) { - printk(KERN_WARNING "INFTL: Unable to read spare " - "Media Header\n"); - return -1; - } - /* Check if this one is the same as the first one we found. */ - if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) { - printk(KERN_WARNING "INFTL: Primary and spare Media " - "Headers disagree.\n"); - return -1; - } - mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); @@ -190,9 +197,8 @@ static int find_boot_record(struct INFTLrecord *inftl) "UnitSizeFactor 0x%02x is experimental\n", mh->BlockMultiplierBits); inftl->EraseSize = inftl->mbd.mtd->erasesize << - mh->BlockMultiplierBits; + (0xff - mh->BlockMultiplierBits); inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; - block >>= mh->BlockMultiplierBits; } /* Scan the partitions */ @@ -287,7 +293,7 @@ static int find_boot_record(struct INFTLrecord *inftl) inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL); if (!inftl->PUtable) { printk(KERN_WARNING "INFTL: allocation of PUtable " - "failed (%zd bytes)\n", + "failed (%d bytes)\n", inftl->nb_blocks * sizeof(u16)); return -ENOMEM; } @@ -296,7 +302,7 @@ static int find_boot_record(struct INFTLrecord *inftl) if (!inftl->VUtable) { kfree(inftl->PUtable); printk(KERN_WARNING "INFTL: allocation of VUtable " - "failed (%zd bytes)\n", + "failed (%d bytes)\n", inftl->nb_blocks * sizeof(u16)); return -ENOMEM; } @@ -311,23 +317,34 @@ static int find_boot_record(struct INFTLrecord *inftl) /* Mark this boot record (NFTL MediaHeader) block as reserved */ inftl->PUtable[block] = BLOCK_RESERVED; +#if 0 /* Read Bad Erase Unit Table and modify PUtable[] accordingly */ for (i = 0; i < inftl->nb_blocks; i++) { - int physblock; - /* If any of the physical eraseblocks are bad, don't - use the unit. */ - for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) { - if (inftl->mbd.mtd->block_isbad(inftl->mbd.mtd, i * inftl->EraseSize + physblock)) - inftl->PUtable[i] = BLOCK_RESERVED; + if ((i & (SECTORSIZE - 1)) == 0) { + /* read one sector for every SECTORSIZE of blocks */ + if ((ret = MTD_READECC(inftl->mbd.mtd, + block * inftl->EraseSize + i + SECTORSIZE, + SECTORSIZE, &retlen, buf, + (char *)&oob, NULL)) < 0) { + printk(KERN_WARNING "INFTL: read of " + "bad sector table failed " + "(err %d)\n", ret); + kfree(inftl->VUtable); + kfree(inftl->PUtable); + return -1; + } } + /* Mark the Bad Erase Unit as RESERVED in PUtable */ + if (buf[i & (SECTORSIZE - 1)] != 0xff) + inftl->PUtable[i] = BLOCK_RESERVED; } +#endif inftl->MediaUnit = block; - return 0; + boot_record_count++; } - - /* Not found. */ - return -1; + + return boot_record_count ? 0 : -1; } static int memcmpb(void *a, int c, int n) @@ -347,22 +364,28 @@ static int memcmpb(void *a, int c, int n) static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, int len, int check_oob) { - u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize]; - size_t retlen; - int i; + int i, retlen; + u8 buf[SECTORSIZE]; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p," - "address=0x%x,len=%d,check_oob=%d)\n", inftl, + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x," + "address=0x%x,len=%d,check_oob=%d)\n", (int)inftl, address, len, check_oob); for (i = 0; i < len; i += SECTORSIZE) { - if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0) + /* + * We want to read the sector without ECC check here since a + * free sector does not have ECC syndrome on it yet. + */ + if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0) return -1; if (memcmpb(buf, 0xff, SECTORSIZE) != 0) return -1; if (check_oob) { - if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0) + if (MTD_READOOB(inftl->mbd.mtd, address, + inftl->mbd.mtd->oobsize, &retlen, buf) < 0) + return -1; + if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0) return -1; } address += SECTORSIZE; @@ -379,62 +402,52 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, * Return: 0 when succeed, -1 on error. * * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * 2. UnitSizeFactor != 0xFF */ int INFTL_formatblock(struct INFTLrecord *inftl, int block) { - size_t retlen; + int retlen; struct inftl_unittail uci; struct erase_info *instr = &inftl->instr; - int physblock; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p," - "block=%d)\n", inftl, block); + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x," + "block=%d)\n", (int)inftl, block); memset(instr, 0, sizeof(struct erase_info)); - /* FIXME: Shouldn't we be setting the 'discarded' flag to zero - _first_? */ - /* Use async erase interface, test return code */ instr->addr = block * inftl->EraseSize; - instr->len = inftl->mbd.mtd->erasesize; - /* Erase one physical eraseblock at a time, even though the NAND api - allows us to group them. This way we if we have a failure, we can - mark only the failed block in the bbt. */ - for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) { - MTD_ERASE(inftl->mbd.mtd, instr); - - if (instr->state == MTD_ERASE_FAILED) { - printk(KERN_WARNING "INFTL: error while formatting block %d\n", - block); - goto fail; - } + instr->len = inftl->EraseSize; + MTD_ERASE(inftl->mbd.mtd, instr); + if (instr->state == MTD_ERASE_FAILED) { /* - * Check the "freeness" of Erase Unit before updating metadata. - * FixMe: is this check really necessary? Since we have check the - * return code after the erase operation. - */ - if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0) - goto fail; + * Could not format, FixMe: We should update the BadUnitTable + * both in memory and on disk. + */ + printk(KERN_WARNING "INFTL: error while formatting block %d\n", + block); + return -1; } + /* + * Check the "freeness" of Erase Unit before updating metadata. + * FixMe: is this check really necessary? Since we have check the + * return code after the erase operation. + */ + if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0) + return -1; + uci.EraseMark = cpu_to_le16(ERASE_MARK); uci.EraseMark1 = cpu_to_le16(ERASE_MARK); uci.Reserved[0] = 0; uci.Reserved[1] = 0; uci.Reserved[2] = 0; uci.Reserved[3] = 0; - instr->addr = block * inftl->EraseSize + SECTORSIZE * 2; - if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr + + if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 + 8, 8, &retlen, (char *)&uci) < 0) - goto fail; + return -1; return 0; -fail: - /* could not format, update the bad block table (caller is responsible - for setting the PUtable to BLOCK_RESERVED on failure) */ - inftl->mbd.mtd->block_markbad(inftl->mbd.mtd, instr->addr); - return -1; } /* @@ -459,6 +472,7 @@ static void format_chain(struct INFTLrecord *inftl, unsigned int first_block) if (INFTL_formatblock(inftl, block) < 0) { /* * Cannot format !!!! Mark it as Bad Unit, + * FixMe: update the BadUnitTable on disk. */ inftl->PUtable[block] = BLOCK_RESERVED; } else { @@ -551,11 +565,10 @@ int INFTL_mount(struct INFTLrecord *s) int chain_length, do_format_chain; struct inftl_unithead1 h0; struct inftl_unittail h1; - size_t retlen; - int i; + int i, retlen; u8 *ANACtable, ANAC; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=%p)\n", s); + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=0x%x)\n", (int)s); /* Search for INFTL MediaHeader and Spare INFTL Media Header */ if (find_boot_record(s) < 0) {