mtd/drivers/mtd inftlmount.c,1.12,1.13 inftlcore.c,1.14,1.15
dbrown at infradead.org
dbrown at infradead.org
Mon Jun 28 12:06:38 EDT 2004
Update of /home/cvs/mtd/drivers/mtd
In directory phoenix.infradead.org:/tmp/cvs-serv4731
Modified Files:
inftlmount.c inftlcore.c
Log Message:
Modified to work with new NAND-based DiskOnChip driver. No longer works with the older drivers!
Index: inftlmount.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/inftlmount.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- inftlmount.c 26 Jun 2003 07:31:36 -0000 1.12
+++ inftlmount.c 28 Jun 2004 16:06:36 -0000 1.13
@@ -54,7 +54,7 @@
{
struct inftl_unittail h1;
//struct inftl_oob oob;
- unsigned int i, block, boot_record_count = 0;
+ unsigned int i, block;
u8 buf[SECTORSIZE];
struct INFTLMediaHeader *mh = &inftl->MediaHdr;
struct INFTLPartition *ip;
@@ -72,7 +72,6 @@
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++) {
@@ -82,8 +81,11 @@
* Check for BNAND header first. Then whinge if it's found
* but later checks fail.
*/
- if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
- SECTORSIZE, &retlen, buf))) {
+ 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) {
static int warncount = 5;
if (warncount) {
@@ -114,36 +116,28 @@
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);
@@ -197,8 +191,9 @@
"UnitSizeFactor 0x%02x is experimental\n",
mh->BlockMultiplierBits);
inftl->EraseSize = inftl->mbd.mtd->erasesize <<
- (0xff - mh->BlockMultiplierBits);
+ mh->BlockMultiplierBits;
inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+ block >>= mh->BlockMultiplierBits;
}
/* Scan the partitions */
@@ -317,34 +312,23 @@
/* 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++) {
- 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;
- }
+ 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;
}
- /* Mark the Bad Erase Unit as RESERVED in PUtable */
- if (buf[i & (SECTORSIZE - 1)] != 0xff)
- inftl->PUtable[i] = BLOCK_RESERVED;
}
-#endif
inftl->MediaUnit = block;
- boot_record_count++;
+ return 0;
}
-
- return boot_record_count ? 0 : -1;
+
+ /* Not found. */
+ return -1;
}
static int memcmpb(void *a, int c, int n)
@@ -365,27 +349,20 @@
int len, int check_oob)
{
int i, retlen;
- u8 buf[SECTORSIZE];
+ u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
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) {
- /*
- * 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)
+ if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1;
if (check_oob) {
- 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)
+ if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
return -1;
}
address += SECTORSIZE;
@@ -402,13 +379,13 @@
* 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)
{
int retlen;
struct inftl_unittail uci;
struct erase_info *instr = &inftl->instr;
+ int physblock;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x,"
"block=%d)\n", (int)inftl, block);
@@ -420,37 +397,44 @@
/* Use async erase interface, test return code */
instr->addr = block * inftl->EraseSize;
- instr->len = inftl->EraseSize;
- MTD_ERASE(inftl->mbd.mtd, instr);
+ 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;
+ }
- if (instr->state == MTD_ERASE_FAILED) {
/*
- * 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, instr->len, 1) != 0)
+ goto fail;
}
- /*
- * 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;
- if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 +
+ instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
+ if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr +
8, 8, &retlen, (char *)&uci) < 0)
- return -1;
+ goto fail;
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;
}
/*
@@ -475,7 +459,6 @@
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 {
Index: inftlcore.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/inftlcore.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- inftlcore.c 26 Jun 2003 08:28:26 -0000 1.14
+++ inftlcore.c 28 Jun 2004 16:06:36 -0000 1.15
@@ -55,9 +55,19 @@
struct INFTLrecord *inftl;
unsigned long temp;
- if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
+ if (mtd->type != MTD_NANDFLASH)
+ return;
+ /* OK, this is moderately ugly. But probably safe. Alternatives? */
+ if (memcmp(mtd->name, "DiskOnChip", 10))
return;
+ if (!mtd->block_isbad) {
+ printk(KERN_ERR
+"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
+"Please use the new diskonchip driver under the NAND subsystem.\n");
+ return;
+ }
+
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
@@ -72,6 +82,8 @@
inftl->mbd.devnum = -1;
inftl->mbd.blksize = 512;
inftl->mbd.tr = tr;
+ memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
+ inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
if (INFTL_mount(inftl) < 0) {
printk(KERN_WARNING "INFTL: could not mount device\n");
@@ -284,21 +296,22 @@
if (BlockMap[block] == BLOCK_NIL)
continue;
- ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+ ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
- &retlen, movebuf, (char *)&oob, NULL);
+ &retlen, movebuf);
if (ret < 0) {
- ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+ ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE),
- SECTORSIZE, &retlen, movebuf, (char *)&oob,
- NULL);
+ SECTORSIZE, &retlen, movebuf);
if (ret != -EIO)
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
"away on retry?\n");
}
+ memset(&oob, 0xff, sizeof(struct inftl_oob));
+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
(block * SECTORSIZE), SECTORSIZE, &retlen,
- movebuf, (char *)&oob, NULL);
+ movebuf, (char *)&oob, &inftl->oobinfo);
}
/*
@@ -326,7 +339,6 @@
if (INFTL_formatblock(inftl, thisEUN) < 0) {
/*
* Could not erase : mark block as reserved.
- * FixMe: Update Bad Unit Table on disk.
*/
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
} else {
@@ -668,7 +680,6 @@
if (INFTL_formatblock(inftl, thisEUN) < 0) {
/*
* Could not erase : mark block as reserved.
- * FixMe: Update Bad Unit Table on medium.
*/
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
} else {
@@ -754,7 +765,7 @@
unsigned int writeEUN;
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
size_t retlen;
- u8 eccbuf[6];
+ struct inftl_oob oob;
char *p, *pend;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%d,"
@@ -778,11 +789,13 @@
return 1;
}
+ memset(&oob, 0xff, sizeof(struct inftl_oob));
+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
blockofs, SECTORSIZE, &retlen, (char *)buffer,
- (char *)eccbuf, NULL);
+ (char *)&oob, &inftl->oobinfo);
/*
- * No need to write SECTOR_USED flags since they are written
+ * need to write SECTOR_USED flags since they are not written
* in mtd_writeecc
*/
} else {
@@ -846,9 +859,8 @@
} else {
size_t retlen;
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
- u_char eccbuf[6];
- if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
- buffer, eccbuf, NULL))
+ if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
+ buffer))
return -EIO;
}
return 0;
More information about the linux-mtd-cvs
mailing list