19 #include <linux/slab.h>
21 #include <linux/module.h>
23 #include <asm/types.h>
29 #define PREFIX "rfd_ftl: "
33 #define RFD_FTL_MAJOR 256
40 #define RFD_MAGIC 0x9193
47 #define HEADER_MAP_OFFSET 3
48 #define SECTOR_DELETED 0x0000
49 #define SECTOR_ZERO 0xfffe
50 #define SECTOR_FREE 0xffff
52 #define SECTOR_SIZE 512
54 #define SECTORS_PER_TRACK 63
92 static int build_block_map(
struct partition *
part,
int block_no)
124 "'%s': unit #%d: entry %d corrupt, "
125 "sector %d out of range\n",
126 part->
mbd.mtd->name, block_no, i, entry);
132 "'%s': more than one entry for sector %d\n",
133 part->
mbd.mtd->name, entry);
150 static int scan_header(
struct partition *part)
152 int sectors_per_block;
195 "sector map", part->
mbd.mtd->name);
213 if (!build_block_map(part, i))
217 if (blocks_found == 0) {
219 part->
mbd.mtd->name);
226 part->
mbd.mtd->name);
260 "0x%lx\n", part->
mbd.mtd->name, addr);
269 static void erase_callback(
struct erase_info *erase)
282 "on '%s'\n", (
unsigned long long)erase->
addr, part->
mbd.mtd->name);
288 "state %d\n", (
unsigned long long)erase->
addr,
291 part->
blocks[
i].state = BLOCK_FAILED;
292 part->
blocks[
i].free_sectors = 0;
293 part->
blocks[
i].used_sectors = 0;
302 part->
blocks[
i].state = BLOCK_ERASED;
304 part->
blocks[
i].used_sectors = 0;
308 &retlen, (
u_char *)&magic);
310 if (!rc && retlen !=
sizeof(magic))
318 part->
blocks[
i].state = BLOCK_FAILED;
326 static int erase_block(
struct partition *part,
int block)
335 erase->
mtd = part->
mbd.mtd;
348 "failed\n", (
unsigned long long)erase->
addr,
349 (
unsigned long long)erase->
len, part->
mbd.mtd->name);
357 static int move_block_contents(
struct partition *part,
int block_no,
u_long *old_sector)
382 "0x%lx\n", part->
mbd.mtd->name,
383 part->
blocks[block_no].offset);
403 addr = part->
blocks[block_no].offset +
406 if (*old_sector == addr) {
408 if (!part->
blocks[block_no].used_sectors--) {
409 rc = erase_block(part, block_no);
422 "read sector for relocation\n",
423 part->
mbd.mtd->name);
447 int block, best_block,
score, old_sector_block;
451 mtd_sync(part->
mbd.mtd);
455 if (*old_sector != -1)
456 old_sector_block = *old_sector / part->
block_size;
458 old_sector_block = -1;
471 if (part->
blocks[block].free_sectors)
476 if (block == old_sector_block)
480 if (part->
blocks[block].used_sectors ==
487 if (this_score < score) {
493 if (best_block == -1)
499 pr_debug(
"reclaim_block: reclaiming block #%d with %d used "
500 "%d free sectors\n", best_block,
501 part->
blocks[best_block].used_sectors,
502 part->
blocks[best_block].free_sectors);
504 if (part->
blocks[best_block].used_sectors)
505 rc = move_block_contents(part, best_block, old_sector);
507 rc = erase_block(part, best_block);
517 static int find_free_block(
struct partition *part)
526 if (part->
blocks[block].free_sectors &&
530 if (part->
blocks[block].state == BLOCK_UNUSED)
531 erase_block(part, block);
536 }
while (block != stop);
541 static int find_writable_block(
struct partition *part,
u_long *old_sector)
546 block = find_free_block(part);
550 rc = reclaim_block(part, old_sector);
554 block = find_free_block(part);
572 "0x%lx\n", part->
mbd.mtd->name,
573 part->
blocks[block].offset);
583 static int mark_sector_deleted(
struct partition *part,
u_long old_addr)
594 addr = part->
blocks[block].offset +
596 rc =
mtd_write(part->
mbd.mtd, addr,
sizeof(del), &retlen,
599 if (!rc && retlen !=
sizeof(del))
604 "0x%lx\n", part->
mbd.mtd->name, addr);
613 if (!part->
blocks[block].used_sectors &&
614 !part->
blocks[block].free_sectors)
615 rc = erase_block(part, block);
621 static int find_free_sector(
const struct partition *part,
const struct block *block)
653 rc = find_writable_block(part, old_addr);
660 i = find_free_sector(part, block);
677 part->
mbd.mtd->name, addr);
689 rc =
mtd_write(part->
mbd.mtd, addr,
sizeof(entry), &retlen,
692 if (!rc && retlen !=
sizeof(entry))
697 part->
mbd.mtd->name, addr);
715 pr_debug(
"rfd_ftl_writesect(sector=0x%lx)\n", sector);
733 rc = do_writesect(dev, sector, buf, &old_addr);
739 if (i == SECTOR_SIZE)
743 rc = mark_sector_deleted(part, old_addr);
783 if (scan_header(part) == 0) {
786 part->
mbd.devnum = -1;
788 part->
mbd.readonly = 1;
791 "setting read-only\n", mtd->
name);
792 part->
mbd.readonly = 1;
811 pr_debug(
"rfd_ftl_remove_dev:'%s': erase unit #%02d: %d erases\n",
812 part->
mbd.mtd->name, i, part->
blocks[i].erases);
827 .readsect = rfd_ftl_readsect,
828 .writesect = rfd_ftl_writesect,
829 .getgeo = rfd_ftl_getgeo,
830 .add_mtd = rfd_ftl_add_mtd,
831 .remove_dev = rfd_ftl_remove_dev,
835 static int __init init_rfd_ftl(
void)
840 static void __exit cleanup_rfd_ftl(
void)
851 "used by General Software's Embedded BIOS");