#define PRERELEASE
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/errno.h>
kfree(nftl);
}
+/*
+ * Read oob data from flash
+ */
+int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs & (mtd->writesize - 1);
+ ops.ooblen = len;
+ ops.oobbuf = buf;
+ ops.datbuf = NULL;
+ ops.len = len;
+
+ res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
+/*
+ * Write oob data to flash
+ */
+int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs & (mtd->writesize - 1);
+ ops.ooblen = len;
+ ops.oobbuf = buf;
+ ops.datbuf = NULL;
+ ops.len = len;
+
+ res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
+/*
+ * Write data and oob to flash
+ */
+static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf, uint8_t *oob)
+{
+ struct mtd_oob_ops ops;
+ int res;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooboffs = offs;
+ ops.ooblen = mtd->oobsize;
+ ops.oobbuf = oob;
+ ops.datbuf = buf;
+ ops.len = len;
+
+ res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
+ *retlen = ops.retlen;
+ return res;
+}
+
#ifdef CONFIG_NFTL_RW
/* Actual NFTL access routines */
targetEUN = thisEUN;
for (block = 0; block < nftl->EraseSize / 512; block ++) {
- mtd->read_oob(mtd, (thisEUN * nftl->EraseSize) +
+ nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
(block * 512), 16 , &retlen,
(char *)&oob);
if (block == 2) {
longer one */
oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
oob.u.c.unused = 0xffffffff;
- mtd->write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
+ nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
8, &retlen, (char *)&oob.u);
}
ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
512, &retlen, movebuf);
- if (ret < 0) {
+ if (ret < 0 && ret != -EUCLEAN) {
ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
+ (block * 512), 512, &retlen,
movebuf);
memset(&oob, 0xff, sizeof(struct nftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED;
- nand_write_raw(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
- (block * 512), 512, &retlen, movebuf,
- (char *)&oob);
-
+ nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
+ (block * 512), 512, &retlen, movebuf, (char *)&oob);
}
/* add the header so that it is now a valid chain */
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
- mtd->write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
+ nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
8, &retlen, (char *)&oob.u);
/* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
lastEUN = writeEUN;
- mtd->read_oob(mtd,
+ nftl_read_oob(mtd,
(writeEUN * nftl->EraseSize) + blockofs,
8, &retlen, (char *)&bci);
nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
/* ... and on the flash itself */
- mtd->read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
+ nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
&retlen, (char *)&oob.u);
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
- mtd->write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
+ nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
&retlen, (char *)&oob.u);
/* we link the new block to the chain only after the
/* Both in our cache... */
nftl->ReplUnitTable[lastEUN] = writeEUN;
/* ... and on the flash itself */
- mtd->read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
+ nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
8, &retlen, (char *)&oob.u);
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
= cpu_to_le16(writeEUN);
- mtd->write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
+ nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
8, &retlen, (char *)&oob.u);
}
memset(&oob, 0xff, sizeof(struct nftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED;
- nand_write_raw(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) +
- blockofs, 512, &retlen, (char *)buffer,
- (char *)&oob);
+ nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
+ 512, &retlen, (char *)buffer, (char *)&oob);
return 0;
}
#endif /* CONFIG_NFTL_RW */
if (thisEUN != BLOCK_NIL) {
while (thisEUN < nftl->nb_blocks) {
- if (mtd->read_oob(mtd, (thisEUN * nftl->EraseSize) +
+ if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
blockofs, 8, &retlen,
(char *)&bci) < 0)
status = SECTOR_IGNORE;
} else {
loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
size_t retlen;
- if (mtd->read(mtd, ptr, 512, &retlen, buffer))
+ int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
+
+ if (res < 0 && res != -EUCLEAN)
return -EIO;
}
return 0;