58 #include <linux/module.h>
62 #include <linux/kernel.h>
63 #include <linux/ptrace.h>
64 #include <linux/slab.h>
65 #include <linux/string.h>
73 #include <asm/uaccess.h>
80 static int shuffle_freq = 50;
106 #define SECTOR_SIZE 512
135 #define FTL_FORMATTED 0x01
138 #define XFER_UNKNOWN 0x00
139 #define XFER_ERASING 0x01
140 #define XFER_ERASED 0x02
141 #define XFER_PREPARED 0x03
142 #define XFER_FAILED 0x04
161 loff_t
offset, max_offset;
165 max_offset = (0x100000<part->
mbd.mtd->size)?0x100000:part->
mbd.mtd->size;
168 (offset +
sizeof(header)) < max_offset;
169 offset += part->
mbd.mtd->erasesize ? : 0x2000) {
171 err =
mtd_read(part->
mbd.mtd, offset,
sizeof(header), &ret,
172 (
unsigned char *)&header);
180 if (offset == max_offset) {
204 int hdr_ok, ret = -1;
216 part->
EUNInfo[i].Offset = 0xffffffff;
227 ret =
mtd_read(part->
mbd.mtd, offset,
sizeof(header), &retval,
228 (
unsigned char *)&header);
245 "transfer units!\n");
282 goto out_VirtualBlockMap;
338 struct xfer_info_t *xfer;
342 pr_debug(
"ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
352 erase->
mtd = part->
mbd.mtd;
353 erase->
callback = ftl_erase_callback;
354 erase->
addr = xfer->Offset;
375 static void ftl_erase_callback(
struct erase_info *erase)
378 struct xfer_info_t *xfer;
389 "erase lookup failed!\n");
409 struct xfer_info_t *xfer;
418 pr_debug(
"ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
425 ret =
mtd_write(part->
mbd.mtd, xfer->Offset,
sizeof(header), &retlen,
439 for (i = 0; i < nbam; i++, offset +=
sizeof(
uint32_t)) {
468 struct eun_info_t *eun;
469 struct xfer_info_t *xfer;
479 pr_debug(
"ftl_cs: copying block 0x%x to 0x%x\n",
480 eun->Offset, xfer->Offset);
503 offset = xfer->Offset + 20;
510 printk(
KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
515 src = eun->Offset; dest = xfer->Offset;
566 &retlen, (
u_char *)&srcunitswap);
575 i = xfer->EraseCount;
576 xfer->EraseCount = eun->EraseCount;
579 xfer->Offset = eun->Offset;
614 pr_debug(
"ftl_cs: reclaiming space...\n");
617 best = 0xffffffff; xfer = 0xffff;
623 pr_debug(
"XferInfo[%d].state == XFER_UNKNOWN\n",i);
628 pr_debug(
"XferInfo[%d].state == XFER_ERASING\n",i);
633 pr_debug(
"XferInfo[%d].state == XFER_ERASED\n",i);
635 prepare_xfer(part, i);
638 pr_debug(
"XferInfo[%d].state == XFER_PREPARED\n",i);
640 if (part->
XferInfo[i].EraseCount <= best) {
649 if (xfer == 0xffff) {
651 pr_debug(
"ftl_cs: waiting for transfer "
652 "unit to be prepared...\n");
653 mtd_sync(part->
mbd.mtd);
658 "suitable transfer units!\n");
660 pr_debug(
"ftl_cs: reclaim failed: no "
661 "suitable transfer units!\n");
666 }
while (xfer == 0xffff);
669 if ((jiffies % shuffle_freq) == 0) {
670 pr_debug(
"ftl_cs: recycling freshest block...\n");
673 if (part->
EUNInfo[i].EraseCount <= best) {
680 if (part->
EUNInfo[i].Deleted >= best) {
688 "no free blocks!\n");
691 "no free blocks!\n");
696 ret = copy_erase_unit(part, eun, xfer);
698 erase_xfer(part, xfer);
741 }
while (eun != stop);
743 if (part->
EUNInfo[eun].Free == 0)
776 pr_debug(
"ftl_cs: found free block at %d in %d\n", blk, eun);
796 pr_debug(
"ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
797 part, sector, nblocks);
804 for (i = 0; i < nblocks; i++) {
810 if (log_addr == 0xffffffff)
811 memset(buffer, 0, SECTOR_SIZE);
813 offset = (part->
EUNInfo[log_addr / bsize].Offset
814 + (log_addr % bsize));
815 ret =
mtd_read(part->
mbd.mtd, offset, SECTOR_SIZE, &retlen,
845 pr_debug(
"ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
846 part, log_addr, virt_addr);
848 eun = log_addr / bsize;
849 blk = (log_addr % bsize) / SECTOR_SIZE;
862 if (((virt_addr == 0xfffffffe) && !
BLOCK_FREE(old_addr)) ||
869 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
897 log_addr, virt_addr);
905 uint32_t bsize, log_addr, virt_addr, old_addr,
blk;
910 pr_debug(
"ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
911 part, sector, nblocks);
918 ret = reclaim_block(part);
925 virt_addr = sector * SECTOR_SIZE |
BLOCK_DATA;
926 for (i = 0; i < nblocks; i++) {
933 blk = find_free(part);
938 "no free blocks!\n");
946 if (set_bam_entry(part, log_addr, 0xfffffffe))
951 ret =
mtd_write(part->
mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer);
956 " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
963 if (old_addr != 0xffffffff) {
965 part->
EUNInfo[old_addr/bsize].Deleted++;
966 if (set_bam_entry(part, old_addr, 0))
971 if (set_bam_entry(part, log_addr, virt_addr))
998 unsigned long block,
char *buf)
1000 return ftl_read((
void *)dev, buf, block, 1);
1004 unsigned long block,
char *buf)
1006 return ftl_write((
void *)dev, buf, block, 1);
1010 unsigned long sector,
unsigned nr_sects)
1015 pr_debug(
"FTL erase sector %ld for %d sectors\n",
1020 if (old_addr != 0xffffffff) {
1022 part->
EUNInfo[old_addr/bsize].Deleted++;
1023 if (set_bam_entry(part, old_addr, 0))
1060 partition->
mbd.mtd = mtd;
1062 if ((scan_header(partition) == 0) &&
1063 (build_maps(partition) == 0)) {
1072 partition->
mbd.tr = tr;
1073 partition->
mbd.devnum = -1;
1078 ftl_freepart(partition);
1093 .readsect = ftl_readsect,
1094 .writesect = ftl_writesect,
1095 .discard = ftl_discardsect,
1096 .getgeo = ftl_getgeo,
1097 .add_mtd = ftl_add_mtd,
1098 .remove_dev = ftl_remove_dev,
1102 static int __init init_ftl(
void)
1107 static void __exit cleanup_ftl(
void)
1118 MODULE_DESCRIPTION(
"Support code for Flash Translation Layer, used on PCMCIA devices");