|
@@ -1,5 +1,5 @@
|
|
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
|
|
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
|
|
- * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
|
|
|
|
|
|
+ * $Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $
|
|
*
|
|
*
|
|
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
|
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
|
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
|
|
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
|
|
@@ -53,7 +53,7 @@
|
|
Use of the FTL format for non-PCMCIA applications may be an
|
|
Use of the FTL format for non-PCMCIA applications may be an
|
|
infringement of these patents. For additional information,
|
|
infringement of these patents. For additional information,
|
|
contact M-Systems (http://www.m-sys.com) directly.
|
|
contact M-Systems (http://www.m-sys.com) directly.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
#include <linux/mtd/blktrans.h>
|
|
#include <linux/mtd/blktrans.h>
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
@@ -160,7 +160,7 @@ static void ftl_erase_callback(struct erase_info *done);
|
|
Scan_header() checks to see if a memory region contains an FTL
|
|
Scan_header() checks to see if a memory region contains an FTL
|
|
partition. build_maps() reads all the erase unit headers, builds
|
|
partition. build_maps() reads all the erase unit headers, builds
|
|
the erase unit map, and then builds the virtual page map.
|
|
the erase unit map, and then builds the virtual page map.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
static int scan_header(partition_t *part)
|
|
static int scan_header(partition_t *part)
|
|
@@ -176,10 +176,10 @@ static int scan_header(partition_t *part)
|
|
(offset + sizeof(header)) < max_offset;
|
|
(offset + sizeof(header)) < max_offset;
|
|
offset += part->mbd.mtd->erasesize ? : 0x2000) {
|
|
offset += part->mbd.mtd->erasesize ? : 0x2000) {
|
|
|
|
|
|
- err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
|
|
|
|
|
|
+ err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
|
|
(unsigned char *)&header);
|
|
(unsigned char *)&header);
|
|
-
|
|
|
|
- if (err)
|
|
|
|
|
|
+
|
|
|
|
+ if (err)
|
|
return err;
|
|
return err;
|
|
|
|
|
|
if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
|
|
if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
|
|
@@ -232,10 +232,10 @@ static int build_maps(partition_t *part)
|
|
for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
|
|
for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
|
|
offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
|
|
offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
|
|
<< part->header.EraseUnitSize);
|
|
<< part->header.EraseUnitSize);
|
|
- ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
|
|
|
|
|
|
+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
|
|
(unsigned char *)&header);
|
|
(unsigned char *)&header);
|
|
-
|
|
|
|
- if (ret)
|
|
|
|
|
|
+
|
|
|
|
+ if (ret)
|
|
goto out_XferInfo;
|
|
goto out_XferInfo;
|
|
|
|
|
|
ret = -1;
|
|
ret = -1;
|
|
@@ -274,7 +274,7 @@ static int build_maps(partition_t *part)
|
|
"don't add up!\n");
|
|
"don't add up!\n");
|
|
goto out_XferInfo;
|
|
goto out_XferInfo;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/* Set up virtual page map */
|
|
/* Set up virtual page map */
|
|
blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
|
|
blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
|
|
part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
|
|
part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
|
|
@@ -296,12 +296,12 @@ static int build_maps(partition_t *part)
|
|
part->EUNInfo[i].Free = 0;
|
|
part->EUNInfo[i].Free = 0;
|
|
part->EUNInfo[i].Deleted = 0;
|
|
part->EUNInfo[i].Deleted = 0;
|
|
offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
|
|
offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
|
|
-
|
|
|
|
- ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
|
|
|
- part->BlocksPerUnit * sizeof(u_int32_t), &retval,
|
|
|
|
|
|
+
|
|
|
|
+ ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
|
|
|
+ part->BlocksPerUnit * sizeof(u_int32_t), &retval,
|
|
(unsigned char *)part->bam_cache);
|
|
(unsigned char *)part->bam_cache);
|
|
-
|
|
|
|
- if (ret)
|
|
|
|
|
|
+
|
|
|
|
+ if (ret)
|
|
goto out_bam_cache;
|
|
goto out_bam_cache;
|
|
|
|
|
|
for (j = 0; j < part->BlocksPerUnit; j++) {
|
|
for (j = 0; j < part->BlocksPerUnit; j++) {
|
|
@@ -316,7 +316,7 @@ static int build_maps(partition_t *part)
|
|
part->EUNInfo[i].Deleted++;
|
|
part->EUNInfo[i].Deleted++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
ret = 0;
|
|
ret = 0;
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -336,7 +336,7 @@ out:
|
|
|
|
|
|
Erase_xfer() schedules an asynchronous erase operation for a
|
|
Erase_xfer() schedules an asynchronous erase operation for a
|
|
transfer unit.
|
|
transfer unit.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
static int erase_xfer(partition_t *part,
|
|
static int erase_xfer(partition_t *part,
|
|
@@ -351,10 +351,10 @@ static int erase_xfer(partition_t *part,
|
|
xfer->state = XFER_ERASING;
|
|
xfer->state = XFER_ERASING;
|
|
|
|
|
|
/* Is there a free erase slot? Always in MTD. */
|
|
/* Is there a free erase slot? Always in MTD. */
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+
|
|
erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
|
|
erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
|
|
- if (!erase)
|
|
|
|
|
|
+ if (!erase)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
erase->mtd = part->mbd.mtd;
|
|
erase->mtd = part->mbd.mtd;
|
|
@@ -362,7 +362,7 @@ static int erase_xfer(partition_t *part,
|
|
erase->addr = xfer->Offset;
|
|
erase->addr = xfer->Offset;
|
|
erase->len = 1 << part->header.EraseUnitSize;
|
|
erase->len = 1 << part->header.EraseUnitSize;
|
|
erase->priv = (u_long)part;
|
|
erase->priv = (u_long)part;
|
|
-
|
|
|
|
|
|
+
|
|
ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
|
|
ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
|
|
|
|
|
|
if (!ret)
|
|
if (!ret)
|
|
@@ -377,7 +377,7 @@ static int erase_xfer(partition_t *part,
|
|
|
|
|
|
Prepare_xfer() takes a freshly erased transfer unit and gives
|
|
Prepare_xfer() takes a freshly erased transfer unit and gives
|
|
it an appropriate header.
|
|
it an appropriate header.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
static void ftl_erase_callback(struct erase_info *erase)
|
|
static void ftl_erase_callback(struct erase_info *erase)
|
|
@@ -385,7 +385,7 @@ static void ftl_erase_callback(struct erase_info *erase)
|
|
partition_t *part;
|
|
partition_t *part;
|
|
struct xfer_info_t *xfer;
|
|
struct xfer_info_t *xfer;
|
|
int i;
|
|
int i;
|
|
-
|
|
|
|
|
|
+
|
|
/* Look up the transfer unit */
|
|
/* Look up the transfer unit */
|
|
part = (partition_t *)(erase->priv);
|
|
part = (partition_t *)(erase->priv);
|
|
|
|
|
|
@@ -422,7 +422,7 @@ static int prepare_xfer(partition_t *part, int i)
|
|
|
|
|
|
xfer = &part->XferInfo[i];
|
|
xfer = &part->XferInfo[i];
|
|
xfer->state = XFER_FAILED;
|
|
xfer->state = XFER_FAILED;
|
|
-
|
|
|
|
|
|
+
|
|
DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
|
|
DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
|
|
|
|
|
|
/* Write the transfer unit header */
|
|
/* Write the transfer unit header */
|
|
@@ -446,7 +446,7 @@ static int prepare_xfer(partition_t *part, int i)
|
|
|
|
|
|
for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
|
|
for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
|
|
|
|
|
|
- ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
|
|
|
|
|
|
+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
|
|
&retlen, (u_char *)&ctl);
|
|
&retlen, (u_char *)&ctl);
|
|
|
|
|
|
if (ret)
|
|
if (ret)
|
|
@@ -454,7 +454,7 @@ static int prepare_xfer(partition_t *part, int i)
|
|
}
|
|
}
|
|
xfer->state = XFER_PREPARED;
|
|
xfer->state = XFER_PREPARED;
|
|
return 0;
|
|
return 0;
|
|
-
|
|
|
|
|
|
+
|
|
} /* prepare_xfer */
|
|
} /* prepare_xfer */
|
|
|
|
|
|
/*======================================================================
|
|
/*======================================================================
|
|
@@ -466,7 +466,7 @@ static int prepare_xfer(partition_t *part, int i)
|
|
All data blocks are copied to the corresponding blocks in the
|
|
All data blocks are copied to the corresponding blocks in the
|
|
target unit, so the virtual block map does not need to be
|
|
target unit, so the virtual block map does not need to be
|
|
updated.
|
|
updated.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
@@ -486,14 +486,14 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
xfer = &part->XferInfo[xferunit];
|
|
xfer = &part->XferInfo[xferunit];
|
|
DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
|
|
DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
|
|
eun->Offset, xfer->Offset);
|
|
eun->Offset, xfer->Offset);
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+
|
|
/* Read current BAM */
|
|
/* Read current BAM */
|
|
if (part->bam_index != srcunit) {
|
|
if (part->bam_index != srcunit) {
|
|
|
|
|
|
offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
|
|
offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
|
|
|
|
|
|
- ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
|
|
|
|
|
+ ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
|
part->BlocksPerUnit * sizeof(u_int32_t),
|
|
part->BlocksPerUnit * sizeof(u_int32_t),
|
|
&retlen, (u_char *) (part->bam_cache));
|
|
&retlen, (u_char *) (part->bam_cache));
|
|
|
|
|
|
@@ -501,11 +501,11 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
part->bam_index = 0xffff;
|
|
part->bam_index = 0xffff;
|
|
|
|
|
|
if (ret) {
|
|
if (ret) {
|
|
- printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
|
|
|
|
|
|
+ printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/* Write the LogicalEUN for the transfer unit */
|
|
/* Write the LogicalEUN for the transfer unit */
|
|
xfer->state = XFER_UNKNOWN;
|
|
xfer->state = XFER_UNKNOWN;
|
|
offset = xfer->Offset + 20; /* Bad! */
|
|
offset = xfer->Offset + 20; /* Bad! */
|
|
@@ -513,12 +513,12 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
|
|
|
|
ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
|
|
ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
|
|
&retlen, (u_char *) &unit);
|
|
&retlen, (u_char *) &unit);
|
|
-
|
|
|
|
|
|
+
|
|
if (ret) {
|
|
if (ret) {
|
|
printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
|
|
printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/* Copy all data blocks from source unit to transfer unit */
|
|
/* Copy all data blocks from source unit to transfer unit */
|
|
src = eun->Offset; dest = xfer->Offset;
|
|
src = eun->Offset; dest = xfer->Offset;
|
|
|
|
|
|
@@ -558,15 +558,15 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
}
|
|
}
|
|
|
|
|
|
/* Write the BAM to the transfer unit */
|
|
/* Write the BAM to the transfer unit */
|
|
- ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
|
|
|
|
- part->BlocksPerUnit * sizeof(int32_t), &retlen,
|
|
|
|
|
|
+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
|
|
|
|
+ part->BlocksPerUnit * sizeof(int32_t), &retlen,
|
|
(u_char *)part->bam_cache);
|
|
(u_char *)part->bam_cache);
|
|
if (ret) {
|
|
if (ret) {
|
|
printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
|
|
printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
|
|
+
|
|
/* All clear? Then update the LogicalEUN again */
|
|
/* All clear? Then update the LogicalEUN again */
|
|
ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
|
|
ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
|
|
&retlen, (u_char *)&srcunitswap);
|
|
&retlen, (u_char *)&srcunitswap);
|
|
@@ -574,9 +574,9 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
if (ret) {
|
|
if (ret) {
|
|
printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
|
|
printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
|
|
return ret;
|
|
return ret;
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
/* Update the maps and usage stats*/
|
|
/* Update the maps and usage stats*/
|
|
i = xfer->EraseCount;
|
|
i = xfer->EraseCount;
|
|
xfer->EraseCount = eun->EraseCount;
|
|
xfer->EraseCount = eun->EraseCount;
|
|
@@ -588,10 +588,10 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
part->FreeTotal += free;
|
|
part->FreeTotal += free;
|
|
eun->Free = free;
|
|
eun->Free = free;
|
|
eun->Deleted = 0;
|
|
eun->Deleted = 0;
|
|
-
|
|
|
|
|
|
+
|
|
/* Now, the cache should be valid for the new block */
|
|
/* Now, the cache should be valid for the new block */
|
|
part->bam_index = srcunit;
|
|
part->bam_index = srcunit;
|
|
-
|
|
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
} /* copy_erase_unit */
|
|
} /* copy_erase_unit */
|
|
|
|
|
|
@@ -608,7 +608,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
|
oldest data unit instead. This means that we generally postpone
|
|
oldest data unit instead. This means that we generally postpone
|
|
the next reclaimation as long as possible, but shuffle static
|
|
the next reclaimation as long as possible, but shuffle static
|
|
stuff around a bit for wear leveling.
|
|
stuff around a bit for wear leveling.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
static int reclaim_block(partition_t *part)
|
|
static int reclaim_block(partition_t *part)
|
|
@@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part)
|
|
else
|
|
else
|
|
DEBUG(1, "ftl_cs: reclaim failed: no "
|
|
DEBUG(1, "ftl_cs: reclaim failed: no "
|
|
"suitable transfer units!\n");
|
|
"suitable transfer units!\n");
|
|
-
|
|
|
|
|
|
+
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -715,7 +715,7 @@ static int reclaim_block(partition_t *part)
|
|
returns the block index -- the erase unit is just the currently
|
|
returns the block index -- the erase unit is just the currently
|
|
cached unit. If there are no free blocks, it returns 0 -- this
|
|
cached unit. If there are no free blocks, it returns 0 -- this
|
|
is never a valid data block because it contains the header.
|
|
is never a valid data block because it contains the header.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
#ifdef PSYCHO_DEBUG
|
|
#ifdef PSYCHO_DEBUG
|
|
@@ -737,7 +737,7 @@ static u_int32_t find_free(partition_t *part)
|
|
u_int32_t blk;
|
|
u_int32_t blk;
|
|
size_t retlen;
|
|
size_t retlen;
|
|
int ret;
|
|
int ret;
|
|
-
|
|
|
|
|
|
+
|
|
/* Find an erase unit with some free space */
|
|
/* Find an erase unit with some free space */
|
|
stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
|
|
stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
|
|
eun = stop;
|
|
eun = stop;
|
|
@@ -749,17 +749,17 @@ static u_int32_t find_free(partition_t *part)
|
|
|
|
|
|
if (part->EUNInfo[eun].Free == 0)
|
|
if (part->EUNInfo[eun].Free == 0)
|
|
return 0;
|
|
return 0;
|
|
-
|
|
|
|
|
|
+
|
|
/* Is this unit's BAM cached? */
|
|
/* Is this unit's BAM cached? */
|
|
if (eun != part->bam_index) {
|
|
if (eun != part->bam_index) {
|
|
/* Invalidate cache */
|
|
/* Invalidate cache */
|
|
part->bam_index = 0xffff;
|
|
part->bam_index = 0xffff;
|
|
|
|
|
|
- ret = part->mbd.mtd->read(part->mbd.mtd,
|
|
|
|
|
|
+ ret = part->mbd.mtd->read(part->mbd.mtd,
|
|
part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
|
|
part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
|
|
part->BlocksPerUnit * sizeof(u_int32_t),
|
|
part->BlocksPerUnit * sizeof(u_int32_t),
|
|
&retlen, (u_char *) (part->bam_cache));
|
|
&retlen, (u_char *) (part->bam_cache));
|
|
-
|
|
|
|
|
|
+
|
|
if (ret) {
|
|
if (ret) {
|
|
printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
|
|
printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
|
|
return 0;
|
|
return 0;
|
|
@@ -781,14 +781,14 @@ static u_int32_t find_free(partition_t *part)
|
|
}
|
|
}
|
|
DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
|
|
DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
|
|
return blk;
|
|
return blk;
|
|
-
|
|
|
|
|
|
+
|
|
} /* find_free */
|
|
} /* find_free */
|
|
|
|
|
|
|
|
|
|
/*======================================================================
|
|
/*======================================================================
|
|
|
|
|
|
Read a series of sectors from an FTL partition.
|
|
Read a series of sectors from an FTL partition.
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
static int ftl_read(partition_t *part, caddr_t buffer,
|
|
static int ftl_read(partition_t *part, caddr_t buffer,
|
|
@@ -798,7 +798,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
|
|
u_long i;
|
|
u_long i;
|
|
int ret;
|
|
int ret;
|
|
size_t offset, retlen;
|
|
size_t offset, retlen;
|
|
-
|
|
|
|
|
|
+
|
|
DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
|
|
DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
|
|
part, sector, nblocks);
|
|
part, sector, nblocks);
|
|
if (!(part->state & FTL_FORMATTED)) {
|
|
if (!(part->state & FTL_FORMATTED)) {
|
|
@@ -834,7 +834,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
|
|
/*======================================================================
|
|
/*======================================================================
|
|
|
|
|
|
Write a series of sectors to an FTL partition
|
|
Write a series of sectors to an FTL partition
|
|
-
|
|
|
|
|
|
+
|
|
======================================================================*/
|
|
======================================================================*/
|
|
|
|
|
|
static int set_bam_entry(partition_t *part, u_int32_t log_addr,
|
|
static int set_bam_entry(partition_t *part, u_int32_t log_addr,
|
|
@@ -855,7 +855,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
|
|
blk = (log_addr % bsize) / SECTOR_SIZE;
|
|
blk = (log_addr % bsize) / SECTOR_SIZE;
|
|
offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
|
|
offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
|
|
le32_to_cpu(part->header.BAMOffset));
|
|
le32_to_cpu(part->header.BAMOffset));
|
|
-
|
|
|
|
|
|
+
|
|
#ifdef PSYCHO_DEBUG
|
|
#ifdef PSYCHO_DEBUG
|
|
ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
|
|
ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
|
|
&retlen, (u_char *)&old_addr);
|
|
&retlen, (u_char *)&old_addr);
|
|
@@ -925,7 +925,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
bsize = 1 << part->header.EraseUnitSize;
|
|
bsize = 1 << part->header.EraseUnitSize;
|
|
|
|
|
|
virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
|
|
virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
|
|
@@ -949,12 +949,12 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
|
log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
|
|
log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
|
|
part->EUNInfo[part->bam_index].Free--;
|
|
part->EUNInfo[part->bam_index].Free--;
|
|
part->FreeTotal--;
|
|
part->FreeTotal--;
|
|
- if (set_bam_entry(part, log_addr, 0xfffffffe))
|
|
|
|
|
|
+ if (set_bam_entry(part, log_addr, 0xfffffffe))
|
|
return -EIO;
|
|
return -EIO;
|
|
part->EUNInfo[part->bam_index].Deleted++;
|
|
part->EUNInfo[part->bam_index].Deleted++;
|
|
offset = (part->EUNInfo[part->bam_index].Offset +
|
|
offset = (part->EUNInfo[part->bam_index].Offset +
|
|
blk * SECTOR_SIZE);
|
|
blk * SECTOR_SIZE);
|
|
- ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
|
|
|
|
|
|
+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
|
|
buffer);
|
|
buffer);
|
|
|
|
|
|
if (ret) {
|
|
if (ret) {
|
|
@@ -964,7 +964,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
|
offset);
|
|
offset);
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/* Only delete the old entry when the new entry is ready */
|
|
/* Only delete the old entry when the new entry is ready */
|
|
old_addr = part->VirtualBlockMap[sector+i];
|
|
old_addr = part->VirtualBlockMap[sector+i];
|
|
if (old_addr != 0xffffffff) {
|
|
if (old_addr != 0xffffffff) {
|
|
@@ -979,7 +979,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
|
return -EIO;
|
|
return -EIO;
|
|
part->VirtualBlockMap[sector+i] = log_addr;
|
|
part->VirtualBlockMap[sector+i] = log_addr;
|
|
part->EUNInfo[part->bam_index].Deleted--;
|
|
part->EUNInfo[part->bam_index].Deleted--;
|
|
-
|
|
|
|
|
|
+
|
|
buffer += SECTOR_SIZE;
|
|
buffer += SECTOR_SIZE;
|
|
virt_addr += SECTOR_SIZE;
|
|
virt_addr += SECTOR_SIZE;
|
|
}
|
|
}
|
|
@@ -1034,20 +1034,20 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
|
partition_t *partition;
|
|
partition_t *partition;
|
|
|
|
|
|
partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
|
|
partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
|
|
-
|
|
|
|
|
|
+
|
|
if (!partition) {
|
|
if (!partition) {
|
|
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
|
|
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
|
|
mtd->name);
|
|
mtd->name);
|
|
return;
|
|
return;
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
memset(partition, 0, sizeof(partition_t));
|
|
memset(partition, 0, sizeof(partition_t));
|
|
|
|
|
|
partition->mbd.mtd = mtd;
|
|
partition->mbd.mtd = mtd;
|
|
|
|
|
|
- if ((scan_header(partition) == 0) &&
|
|
|
|
|
|
+ if ((scan_header(partition) == 0) &&
|
|
(build_maps(partition) == 0)) {
|
|
(build_maps(partition) == 0)) {
|
|
-
|
|
|
|
|
|
+
|
|
partition->state = FTL_FORMATTED;
|
|
partition->state = FTL_FORMATTED;
|
|
#ifdef PCMCIA_DEBUG
|
|
#ifdef PCMCIA_DEBUG
|
|
printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
|
|
printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
|
|
@@ -1086,7 +1086,7 @@ struct mtd_blktrans_ops ftl_tr = {
|
|
|
|
|
|
int init_ftl(void)
|
|
int init_ftl(void)
|
|
{
|
|
{
|
|
- DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
|
|
|
|
|
|
+ DEBUG(0, "$Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $\n");
|
|
|
|
|
|
return register_mtd_blktrans(&ftl_tr);
|
|
return register_mtd_blktrans(&ftl_tr);
|
|
}
|
|
}
|