|
@@ -183,6 +183,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
|
|
|
|
|
|
static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
|
|
static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
|
|
{
|
|
{
|
|
|
|
+ struct mtd_info *mtd = nftl->mbd.mtd;
|
|
u16 BlockMap[MAX_SECTORS_PER_UNIT];
|
|
u16 BlockMap[MAX_SECTORS_PER_UNIT];
|
|
unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
|
|
unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
|
|
unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
|
|
unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
|
|
@@ -192,7 +193,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|
unsigned int targetEUN;
|
|
unsigned int targetEUN;
|
|
struct nftl_oob oob;
|
|
struct nftl_oob oob;
|
|
int inplace = 1;
|
|
int inplace = 1;
|
|
- size_t retlen;
|
|
|
|
|
|
+ size_t retlen;
|
|
|
|
|
|
memset(BlockMap, 0xff, sizeof(BlockMap));
|
|
memset(BlockMap, 0xff, sizeof(BlockMap));
|
|
memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
|
|
memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
|
|
@@ -208,21 +209,21 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|
/* Scan to find the Erase Unit which holds the actual data for each
|
|
/* Scan to find the Erase Unit which holds the actual data for each
|
|
512-byte block within the Chain.
|
|
512-byte block within the Chain.
|
|
*/
|
|
*/
|
|
- silly = MAX_LOOPS;
|
|
|
|
|
|
+ silly = MAX_LOOPS;
|
|
targetEUN = BLOCK_NIL;
|
|
targetEUN = BLOCK_NIL;
|
|
while (thisEUN <= nftl->lastEUN ) {
|
|
while (thisEUN <= nftl->lastEUN ) {
|
|
- unsigned int status, foldmark;
|
|
|
|
|
|
+ unsigned int status, foldmark;
|
|
|
|
|
|
targetEUN = thisEUN;
|
|
targetEUN = thisEUN;
|
|
for (block = 0; block < nftl->EraseSize / 512; block ++) {
|
|
for (block = 0; block < nftl->EraseSize / 512; block ++) {
|
|
- MTD_READOOB(nftl->mbd.mtd,
|
|
|
|
- (thisEUN * nftl->EraseSize) + (block * 512),
|
|
|
|
- 16 , &retlen, (char *)&oob);
|
|
|
|
|
|
+ mtd->read_oob(mtd, (thisEUN * nftl->EraseSize) +
|
|
|
|
+ (block * 512), 16 , &retlen,
|
|
|
|
+ (char *)&oob);
|
|
if (block == 2) {
|
|
if (block == 2) {
|
|
- foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
|
|
|
|
- if (foldmark == FOLD_MARK_IN_PROGRESS) {
|
|
|
|
- DEBUG(MTD_DEBUG_LEVEL1,
|
|
|
|
- "Write Inhibited on EUN %d\n", thisEUN);
|
|
|
|
|
|
+ foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
|
|
|
|
+ if (foldmark == FOLD_MARK_IN_PROGRESS) {
|
|
|
|
+ DEBUG(MTD_DEBUG_LEVEL1,
|
|
|
|
+ "Write Inhibited on EUN %d\n", thisEUN);
|
|
inplace = 0;
|
|
inplace = 0;
|
|
} else {
|
|
} else {
|
|
/* There's no other reason not to do inplace,
|
|
/* There's no other reason not to do inplace,
|
|
@@ -231,7 +232,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|
inplace = 1;
|
|
inplace = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- status = oob.b.Status | oob.b.Status1;
|
|
|
|
|
|
+ status = oob.b.Status | oob.b.Status1;
|
|
BlockLastState[block] = status;
|
|
BlockLastState[block] = status;
|
|
|
|
|
|
switch(status) {
|
|
switch(status) {
|
|
@@ -326,15 +327,15 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|
return BLOCK_NIL;
|
|
return BLOCK_NIL;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- /* We put a fold mark in the chain we are folding only if
|
|
|
|
- we fold in place to help the mount check code. If we do
|
|
|
|
- not fold in place, it is possible to find the valid
|
|
|
|
- chain by selecting the longer one */
|
|
|
|
- oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
|
|
|
|
- oob.u.c.unused = 0xffffffff;
|
|
|
|
- MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
|
|
|
|
- 8, &retlen, (char *)&oob.u);
|
|
|
|
- }
|
|
|
|
|
|
+ /* We put a fold mark in the chain we are folding only if we
|
|
|
|
+ fold in place to help the mount check code. If we do not fold in
|
|
|
|
+ place, it is possible to find the valid chain by selecting the
|
|
|
|
+ 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,
|
|
|
|
+ 8, &retlen, (char *)&oob.u);
|
|
|
|
+ }
|
|
|
|
|
|
/* OK. We now know the location of every block in the Virtual Unit Chain,
|
|
/* OK. We now know the location of every block in the Virtual Unit Chain,
|
|
and the Erase Unit into which we are supposed to be copying.
|
|
and the Erase Unit into which we are supposed to be copying.
|
|
@@ -351,20 +352,20 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
- /* copy only in non free block (free blocks can only
|
|
|
|
|
|
+ /* copy only in non free block (free blocks can only
|
|
happen in case of media errors or deleted blocks) */
|
|
happen in case of media errors or deleted blocks) */
|
|
- if (BlockMap[block] == BLOCK_NIL)
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
|
|
|
|
- 512, &retlen, movebuf);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
|
|
|
|
- + (block * 512), 512, &retlen,
|
|
|
|
- movebuf);
|
|
|
|
- if (ret != -EIO)
|
|
|
|
- printk("Error went away on retry.\n");
|
|
|
|
- }
|
|
|
|
|
|
+ if (BlockMap[block] == BLOCK_NIL)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
|
|
|
|
+ 512, &retlen, movebuf);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
|
|
|
|
+ + (block * 512), 512, &retlen,
|
|
|
|
+ movebuf);
|
|
|
|
+ if (ret != -EIO)
|
|
|
|
+ printk("Error went away on retry.\n");
|
|
|
|
+ }
|
|
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
|
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
|
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
|
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
|
|
|
|
|
@@ -374,13 +375,12 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- /* 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;
|
|
|
|
|
|
+ /* 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_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
|
|
|
|
- 8, &retlen, (char *)&oob.u);
|
|
|
|
|
|
+ mtd->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. */
|
|
/* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
|
|
|
|
|
|
@@ -397,18 +397,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|
while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
|
|
while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
|
|
unsigned int EUNtmp;
|
|
unsigned int EUNtmp;
|
|
|
|
|
|
- EUNtmp = nftl->ReplUnitTable[thisEUN];
|
|
|
|
|
|
+ EUNtmp = nftl->ReplUnitTable[thisEUN];
|
|
|
|
|
|
- if (NFTL_formatblock(nftl, thisEUN) < 0) {
|
|
|
|
|
|
+ if (NFTL_formatblock(nftl, thisEUN) < 0) {
|
|
/* could not erase : mark block as reserved
|
|
/* could not erase : mark block as reserved
|
|
*/
|
|
*/
|
|
nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
|
|
nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
|
|
- } else {
|
|
|
|
|
|
+ } else {
|
|
/* correctly erased : mark it as free */
|
|
/* correctly erased : mark it as free */
|
|
nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
|
|
nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
|
|
nftl->numfreeEUNs++;
|
|
nftl->numfreeEUNs++;
|
|
- }
|
|
|
|
- thisEUN = EUNtmp;
|
|
|
|
|
|
+ }
|
|
|
|
+ thisEUN = EUNtmp;
|
|
}
|
|
}
|
|
|
|
|
|
/* Make this the new start of chain for thisVUC */
|
|
/* Make this the new start of chain for thisVUC */
|
|
@@ -474,6 +474,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
|
{
|
|
{
|
|
u16 lastEUN;
|
|
u16 lastEUN;
|
|
u16 thisVUC = block / (nftl->EraseSize / 512);
|
|
u16 thisVUC = block / (nftl->EraseSize / 512);
|
|
|
|
+ struct mtd_info *mtd = nftl->mbd.mtd;
|
|
unsigned int writeEUN;
|
|
unsigned int writeEUN;
|
|
unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
|
|
unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
|
|
size_t retlen;
|
|
size_t retlen;
|
|
@@ -490,21 +491,22 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
|
*/
|
|
*/
|
|
lastEUN = BLOCK_NIL;
|
|
lastEUN = BLOCK_NIL;
|
|
writeEUN = nftl->EUNtable[thisVUC];
|
|
writeEUN = nftl->EUNtable[thisVUC];
|
|
- silly = MAX_LOOPS;
|
|
|
|
|
|
+ silly = MAX_LOOPS;
|
|
while (writeEUN <= nftl->lastEUN) {
|
|
while (writeEUN <= nftl->lastEUN) {
|
|
struct nftl_bci bci;
|
|
struct nftl_bci bci;
|
|
size_t retlen;
|
|
size_t retlen;
|
|
- unsigned int status;
|
|
|
|
|
|
+ unsigned int status;
|
|
|
|
|
|
lastEUN = writeEUN;
|
|
lastEUN = writeEUN;
|
|
|
|
|
|
- MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
|
|
|
|
- 8, &retlen, (char *)&bci);
|
|
|
|
|
|
+ mtd->read_oob(mtd,
|
|
|
|
+ (writeEUN * nftl->EraseSize) + blockofs,
|
|
|
|
+ 8, &retlen, (char *)&bci);
|
|
|
|
|
|
DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
|
|
DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
|
|
block , writeEUN, le16_to_cpu(bci.Status));
|
|
block , writeEUN, le16_to_cpu(bci.Status));
|
|
|
|
|
|
- status = bci.Status | bci.Status1;
|
|
|
|
|
|
+ status = bci.Status | bci.Status1;
|
|
switch(status) {
|
|
switch(status) {
|
|
case SECTOR_FREE:
|
|
case SECTOR_FREE:
|
|
return writeEUN;
|
|
return writeEUN;
|
|
@@ -575,10 +577,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
|
/* We've found a free block. Insert it into the chain. */
|
|
/* We've found a free block. Insert it into the chain. */
|
|
|
|
|
|
if (lastEUN != BLOCK_NIL) {
|
|
if (lastEUN != BLOCK_NIL) {
|
|
- thisVUC |= 0x8000; /* It's a replacement block */
|
|
|
|
|
|
+ thisVUC |= 0x8000; /* It's a replacement block */
|
|
} else {
|
|
} else {
|
|
- /* The first block in a new chain */
|
|
|
|
- nftl->EUNtable[thisVUC] = writeEUN;
|
|
|
|
|
|
+ /* The first block in a new chain */
|
|
|
|
+ nftl->EUNtable[thisVUC] = writeEUN;
|
|
}
|
|
}
|
|
|
|
|
|
/* set up the actual EUN we're writing into */
|
|
/* set up the actual EUN we're writing into */
|
|
@@ -586,29 +588,29 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
|
nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
|
|
nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
|
|
|
|
|
|
/* ... and on the flash itself */
|
|
/* ... and on the flash itself */
|
|
- MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
|
|
|
|
- &retlen, (char *)&oob.u);
|
|
|
|
|
|
+ mtd->read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
|
|
|
|
+ &retlen, (char *)&oob.u);
|
|
|
|
|
|
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
|
|
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
|
|
|
|
|
|
- MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
|
|
|
|
- &retlen, (char *)&oob.u);
|
|
|
|
|
|
+ mtd->write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
|
|
|
|
+ &retlen, (char *)&oob.u);
|
|
|
|
|
|
- /* we link the new block to the chain only after the
|
|
|
|
|
|
+ /* we link the new block to the chain only after the
|
|
block is ready. It avoids the case where the chain
|
|
block is ready. It avoids the case where the chain
|
|
could point to a free block */
|
|
could point to a free block */
|
|
- if (lastEUN != BLOCK_NIL) {
|
|
|
|
|
|
+ if (lastEUN != BLOCK_NIL) {
|
|
/* Both in our cache... */
|
|
/* Both in our cache... */
|
|
nftl->ReplUnitTable[lastEUN] = writeEUN;
|
|
nftl->ReplUnitTable[lastEUN] = writeEUN;
|
|
/* ... and on the flash itself */
|
|
/* ... and on the flash itself */
|
|
- MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
|
|
|
|
- 8, &retlen, (char *)&oob.u);
|
|
|
|
|
|
+ mtd->read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
|
|
|
|
+ 8, &retlen, (char *)&oob.u);
|
|
|
|
|
|
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
|
|
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
|
|
= cpu_to_le16(writeEUN);
|
|
= cpu_to_le16(writeEUN);
|
|
|
|
|
|
- MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
|
|
|
|
- 8, &retlen, (char *)&oob.u);
|
|
|
|
|
|
+ mtd->write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
|
|
|
|
+ 8, &retlen, (char *)&oob.u);
|
|
}
|
|
}
|
|
|
|
|
|
return writeEUN;
|
|
return writeEUN;
|
|
@@ -652,20 +654,22 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
|
char *buffer)
|
|
char *buffer)
|
|
{
|
|
{
|
|
struct NFTLrecord *nftl = (void *)mbd;
|
|
struct NFTLrecord *nftl = (void *)mbd;
|
|
|
|
+ struct mtd_info *mtd = nftl->mbd.mtd;
|
|
u16 lastgoodEUN;
|
|
u16 lastgoodEUN;
|
|
u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
|
|
u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
|
|
unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
|
|
unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
|
|
- unsigned int status;
|
|
|
|
|
|
+ unsigned int status;
|
|
int silly = MAX_LOOPS;
|
|
int silly = MAX_LOOPS;
|
|
- size_t retlen;
|
|
|
|
- struct nftl_bci bci;
|
|
|
|
|
|
+ size_t retlen;
|
|
|
|
+ struct nftl_bci bci;
|
|
|
|
|
|
lastgoodEUN = BLOCK_NIL;
|
|
lastgoodEUN = BLOCK_NIL;
|
|
|
|
|
|
- if (thisEUN != BLOCK_NIL) {
|
|
|
|
|
|
+ if (thisEUN != BLOCK_NIL) {
|
|
while (thisEUN < nftl->nb_blocks) {
|
|
while (thisEUN < nftl->nb_blocks) {
|
|
- if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs,
|
|
|
|
- 8, &retlen, (char *)&bci) < 0)
|
|
|
|
|
|
+ if (mtd->read_oob(mtd, (thisEUN * nftl->EraseSize) +
|
|
|
|
+ blockofs, 8, &retlen,
|
|
|
|
+ (char *)&bci) < 0)
|
|
status = SECTOR_IGNORE;
|
|
status = SECTOR_IGNORE;
|
|
else
|
|
else
|
|
status = bci.Status | bci.Status1;
|
|
status = bci.Status | bci.Status1;
|
|
@@ -695,7 +699,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
|
}
|
|
}
|
|
thisEUN = nftl->ReplUnitTable[thisEUN];
|
|
thisEUN = nftl->ReplUnitTable[thisEUN];
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
the_end:
|
|
the_end:
|
|
if (lastgoodEUN == BLOCK_NIL) {
|
|
if (lastgoodEUN == BLOCK_NIL) {
|
|
@@ -704,7 +708,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
|
} else {
|
|
} else {
|
|
loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
|
|
loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
|
|
size_t retlen;
|
|
size_t retlen;
|
|
- if (MTD_READ(nftl->mbd.mtd, ptr, 512, &retlen, buffer))
|
|
|
|
|
|
+ if (mtd->read(mtd, ptr, 512, &retlen, buffer))
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
return 0;
|
|
return 0;
|