1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
3 * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
4 * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
8 /*======================================================================
10 A Flash Translation Layer memory card driver
12 This driver implements a disk-like block device driver with an
13 apparent block size of 512 bytes for flash memory cards.
15 ftl_cs.c 1.62 2000/02/01 00:59:04
17 The contents of this file are subject to the Mozilla Public
18 License Version 1.1 (the "License"); you may not use this file
19 except in compliance with the License. You may obtain a copy of
20 the License at http://www.mozilla.org/MPL/
22 Software distributed under the License is distributed on an "AS
23 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
24 implied. See the License for the specific language governing
25 rights and limitations under the License.
27 The initial developer of the original code is David A. Hinds
28 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
29 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
31 Alternatively, the contents of this file may be used under the
32 terms of the GNU General Public License version 2 (the "GPL"), in
33 which case the provisions of the GPL are applicable instead of the
34 above. If you wish to allow the use of your version of this file
35 only under the terms of the GPL and not to allow others to use
36 your version of this file under the MPL, indicate your decision
37 by deleting the provisions above and replace them with the notice
38 and other provisions required by the GPL. If you do not delete
39 the provisions above, a recipient may use your version of this
40 file under either the MPL or the GPL.
42 LEGAL NOTE: The FTL format is patented by M-Systems. They have
43 granted a license for its use with PCMCIA devices:
45 "M-Systems grants a royalty-free, non-exclusive license under
46 any presently existing M-Systems intellectual property rights
47 necessary for the design and development of FTL-compatible
48 drivers, file systems and utilities using the data formats with
49 PCMCIA PC Cards as described in the PCMCIA Flash Translation
50 Layer (FTL) Specification."
52 Use of the FTL format for non-PCMCIA applications may be an
53 infringement of these patents. For additional information,
54 contact M-Systems (http://www.m-sys.com) directly.
56 ======================================================================*/
57 #include <linux/mtd/blktrans.h>
58 #include <linux/module.h>
59 #include <linux/mtd/mtd.h>
60 /*#define PSYCHO_DEBUG */
62 #include <linux/kernel.h>
63 #include <linux/ptrace.h>
64 #include <linux/slab.h>
65 #include <linux/string.h>
66 #include <linux/timer.h>
67 #include <linux/major.h>
69 #include <linux/init.h>
70 #include <linux/hdreg.h>
71 #include <linux/vmalloc.h>
72 #include <linux/blkpg.h>
73 #include <asm/uaccess.h>
75 #include <linux/mtd/ftl.h>
77 /*====================================================================*/
79 /* Parameters that can be set with 'insmod' */
80 static int shuffle_freq = 50;
81 module_param(shuffle_freq, int, 0);
83 /*====================================================================*/
85 /* Major device # for FTL device */
91 /*====================================================================*/
93 /* Maximum number of separate memory devices we'll allow */
96 /* Maximum number of regions per device */
99 /* Maximum number of partitions in an FTL region */
102 /* Maximum number of outstanding erase requests per socket */
105 /* Sector size -- shouldn't need to change */
106 #define SECTOR_SIZE 512
109 /* Each memory region corresponds to a minor device */
110 typedef struct partition_t {
111 struct mtd_blktrans_dev mbd;
113 u_int32_t *VirtualBlockMap;
114 u_int32_t *VirtualPageMap;
118 u_int32_t EraseCount;
124 u_int32_t EraseCount;
128 u_int32_t *bam_cache;
130 u_int32_t BlocksPerUnit;
131 erase_unit_header_t header;
133 region_info_t region;
134 memory_handle_t handle;
138 /* Partition state flags */
139 #define FTL_FORMATTED 0x01
141 /* Transfer unit states */
142 #define XFER_UNKNOWN 0x00
143 #define XFER_ERASING 0x01
144 #define XFER_ERASED 0x02
145 #define XFER_PREPARED 0x03
146 #define XFER_FAILED 0x04
148 /*====================================================================*/
151 static void ftl_erase_callback(struct erase_info *done);
154 /*======================================================================
156 Scan_header() checks to see if a memory region contains an FTL
157 partition. build_maps() reads all the erase unit headers, builds
158 the erase unit map, and then builds the virtual page map.
160 ======================================================================*/
162 static int scan_header(partition_t *part)
164 erase_unit_header_t header;
165 loff_t offset, max_offset;
168 part->header.FormattedSize = 0;
169 max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
170 /* Search first megabyte for a valid FTL header */
172 (offset + sizeof(header)) < max_offset;
173 offset += part->mbd.mtd->erasesize ? : 0x2000) {
175 err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
176 (unsigned char *)&header);
181 if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
184 if (offset == max_offset) {
185 printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
188 if (header.BlockSize != 9 ||
189 (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
190 (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
191 printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
194 if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
195 printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
196 1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
199 part->header = header;
203 static int build_maps(partition_t *part)
205 erase_unit_header_t header;
206 u_int16_t xvalid, xtrans, i;
208 int hdr_ok, ret = -1;
212 /* Set up erase unit maps */
213 part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
214 part->header.NumTransferUnits;
215 part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
219 for (i = 0; i < part->DataUnits; i++)
220 part->EUNInfo[i].Offset = 0xffffffff;
222 kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
228 for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
229 offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
230 << part->header.EraseUnitSize);
231 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
232 (unsigned char *)&header);
238 /* Is this a transfer partition? */
239 hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
240 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
241 (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
242 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
243 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
244 le32_to_cpu(header.EraseCount);
247 if (xtrans == part->header.NumTransferUnits) {
248 printk(KERN_NOTICE "ftl_cs: format error: too many "
249 "transfer units!\n");
252 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
253 part->XferInfo[xtrans].state = XFER_PREPARED;
254 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
256 part->XferInfo[xtrans].state = XFER_UNKNOWN;
257 /* Pick anything reasonable for the erase count */
258 part->XferInfo[xtrans].EraseCount =
259 le32_to_cpu(part->header.EraseCount);
261 part->XferInfo[xtrans].Offset = offset;
265 /* Check for format trouble */
266 header = part->header;
267 if ((xtrans != header.NumTransferUnits) ||
268 (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
269 printk(KERN_NOTICE "ftl_cs: format error: erase units "
274 /* Set up virtual page map */
275 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
276 part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
277 if (!part->VirtualBlockMap)
280 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
281 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
283 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
285 if (!part->bam_cache)
286 goto out_VirtualBlockMap;
288 part->bam_index = 0xffff;
291 for (i = 0; i < part->DataUnits; i++) {
292 part->EUNInfo[i].Free = 0;
293 part->EUNInfo[i].Deleted = 0;
294 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
296 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
297 part->BlocksPerUnit * sizeof(u_int32_t), &retval,
298 (unsigned char *)part->bam_cache);
303 for (j = 0; j < part->BlocksPerUnit; j++) {
304 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
305 part->EUNInfo[i].Free++;
307 } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
308 (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
309 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
310 (i << header.EraseUnitSize) + (j << header.BlockSize);
311 else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
312 part->EUNInfo[i].Deleted++;
320 kfree(part->bam_cache);
322 vfree(part->VirtualBlockMap);
324 kfree(part->XferInfo);
326 kfree(part->EUNInfo);
331 /*======================================================================
333 Erase_xfer() schedules an asynchronous erase operation for a
336 ======================================================================*/
338 static int erase_xfer(partition_t *part,
342 struct xfer_info_t *xfer;
343 struct erase_info *erase;
345 xfer = &part->XferInfo[xfernum];
346 DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
347 xfer->state = XFER_ERASING;
349 /* Is there a free erase slot? Always in MTD. */
352 erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
356 erase->mtd = part->mbd.mtd;
357 erase->callback = ftl_erase_callback;
358 erase->addr = xfer->Offset;
359 erase->len = 1 << part->header.EraseUnitSize;
360 erase->priv = (u_long)part;
362 ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
372 /*======================================================================
374 Prepare_xfer() takes a freshly erased transfer unit and gives
375 it an appropriate header.
377 ======================================================================*/
379 static void ftl_erase_callback(struct erase_info *erase)
382 struct xfer_info_t *xfer;
385 /* Look up the transfer unit */
386 part = (partition_t *)(erase->priv);
388 for (i = 0; i < part->header.NumTransferUnits; i++)
389 if (part->XferInfo[i].Offset == erase->addr) break;
391 if (i == part->header.NumTransferUnits) {
392 printk(KERN_NOTICE "ftl_cs: internal error: "
393 "erase lookup failed!\n");
397 xfer = &part->XferInfo[i];
398 if (erase->state == MTD_ERASE_DONE)
399 xfer->state = XFER_ERASED;
401 xfer->state = XFER_FAILED;
402 printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
408 } /* ftl_erase_callback */
410 static int prepare_xfer(partition_t *part, int i)
412 erase_unit_header_t header;
413 struct xfer_info_t *xfer;
419 xfer = &part->XferInfo[i];
420 xfer->state = XFER_FAILED;
422 DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
424 /* Write the transfer unit header */
425 header = part->header;
426 header.LogicalEUN = cpu_to_le16(0xffff);
427 header.EraseCount = cpu_to_le32(xfer->EraseCount);
429 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
430 &retlen, (u_char *)&header);
436 /* Write the BAM stub */
437 nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
438 le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
440 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
441 ctl = cpu_to_le32(BLOCK_CONTROL);
443 for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
445 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
446 &retlen, (u_char *)&ctl);
451 xfer->state = XFER_PREPARED;
456 /*======================================================================
458 Copy_erase_unit() takes a full erase block and a transfer unit,
459 copies everything to the transfer unit, then swaps the block
462 All data blocks are copied to the corresponding blocks in the
463 target unit, so the virtual block map does not need to be
466 ======================================================================*/
468 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
471 u_char buf[SECTOR_SIZE];
472 struct eun_info_t *eun;
473 struct xfer_info_t *xfer;
474 u_int32_t src, dest, free, i;
479 u_int16_t srcunitswap = cpu_to_le16(srcunit);
481 eun = &part->EUNInfo[srcunit];
482 xfer = &part->XferInfo[xferunit];
483 DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
484 eun->Offset, xfer->Offset);
487 /* Read current BAM */
488 if (part->bam_index != srcunit) {
490 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
492 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
493 part->BlocksPerUnit * sizeof(u_int32_t),
494 &retlen, (u_char *) (part->bam_cache));
496 /* mark the cache bad, in case we get an error later */
497 part->bam_index = 0xffff;
500 printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
505 /* Write the LogicalEUN for the transfer unit */
506 xfer->state = XFER_UNKNOWN;
507 offset = xfer->Offset + 20; /* Bad! */
508 unit = cpu_to_le16(0x7fff);
510 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
511 &retlen, (u_char *) &unit);
514 printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
518 /* Copy all data blocks from source unit to transfer unit */
519 src = eun->Offset; dest = xfer->Offset;
523 for (i = 0; i < part->BlocksPerUnit; i++) {
524 switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
526 /* This gets updated later */
529 case BLOCK_REPLACEMENT:
530 ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
531 &retlen, (u_char *) buf);
533 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
538 ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
539 &retlen, (u_char *) buf);
541 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
547 /* All other blocks must be free */
548 part->bam_cache[i] = cpu_to_le32(0xffffffff);
556 /* Write the BAM to the transfer unit */
557 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
558 part->BlocksPerUnit * sizeof(int32_t), &retlen,
559 (u_char *)part->bam_cache);
561 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
566 /* All clear? Then update the LogicalEUN again */
567 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
568 &retlen, (u_char *)&srcunitswap);
571 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
576 /* Update the maps and usage stats*/
577 i = xfer->EraseCount;
578 xfer->EraseCount = eun->EraseCount;
581 xfer->Offset = eun->Offset;
583 part->FreeTotal -= eun->Free;
584 part->FreeTotal += free;
588 /* Now, the cache should be valid for the new block */
589 part->bam_index = srcunit;
592 } /* copy_erase_unit */
594 /*======================================================================
596 reclaim_block() picks a full erase unit and a transfer unit and
597 then calls copy_erase_unit() to copy one to the other. Then, it
598 schedules an erase on the expired block.
600 What's a good way to decide which transfer unit and which erase
601 unit to use? Beats me. My way is to always pick the transfer
602 unit with the fewest erases, and usually pick the data unit with
603 the most deleted blocks. But with a small probability, pick the
604 oldest data unit instead. This means that we generally postpone
605 the next reclaimation as long as possible, but shuffle static
606 stuff around a bit for wear leveling.
608 ======================================================================*/
610 static int reclaim_block(partition_t *part)
612 u_int16_t i, eun, xfer;
616 DEBUG(0, "ftl_cs: reclaiming space...\n");
617 DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
618 /* Pick the least erased transfer unit */
619 best = 0xffffffff; xfer = 0xffff;
622 for (i = 0; i < part->header.NumTransferUnits; i++) {
624 if (part->XferInfo[i].state == XFER_UNKNOWN) {
625 DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
629 if (part->XferInfo[i].state == XFER_ERASING) {
630 DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
634 else if (part->XferInfo[i].state == XFER_ERASED) {
635 DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
637 prepare_xfer(part, i);
639 if (part->XferInfo[i].state == XFER_PREPARED) {
640 DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
642 if (part->XferInfo[i].EraseCount <= best) {
643 best = part->XferInfo[i].EraseCount;
648 DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
651 if (xfer == 0xffff) {
653 DEBUG(1, "ftl_cs: waiting for transfer "
654 "unit to be prepared...\n");
655 if (part->mbd.mtd->sync)
656 part->mbd.mtd->sync(part->mbd.mtd);
660 printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
661 "suitable transfer units!\n");
663 DEBUG(1, "ftl_cs: reclaim failed: no "
664 "suitable transfer units!\n");
669 } while (xfer == 0xffff);
672 if ((jiffies % shuffle_freq) == 0) {
673 DEBUG(1, "ftl_cs: recycling freshest block...\n");
675 for (i = 0; i < part->DataUnits; i++)
676 if (part->EUNInfo[i].EraseCount <= best) {
677 best = part->EUNInfo[i].EraseCount;
682 for (i = 0; i < part->DataUnits; i++)
683 if (part->EUNInfo[i].Deleted >= best) {
684 best = part->EUNInfo[i].Deleted;
690 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
691 "no free blocks!\n");
693 DEBUG(1,"ftl_cs: reclaim failed: "
694 "no free blocks!\n");
699 ret = copy_erase_unit(part, eun, xfer);
701 erase_xfer(part, xfer);
703 printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
705 } /* reclaim_block */
707 /*======================================================================
709 Find_free() searches for a free block. If necessary, it updates
710 the BAM cache for the erase unit containing the free block. It
711 returns the block index -- the erase unit is just the currently
712 cached unit. If there are no free blocks, it returns 0 -- this
713 is never a valid data block because it contains the header.
715 ======================================================================*/
718 static void dump_lists(partition_t *part)
721 printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
722 for (i = 0; i < part->DataUnits; i++)
723 printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
725 part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
726 part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
730 static u_int32_t find_free(partition_t *part)
737 /* Find an erase unit with some free space */
738 stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
741 if (part->EUNInfo[eun].Free != 0) break;
742 /* Wrap around at end of table */
743 if (++eun == part->DataUnits) eun = 0;
744 } while (eun != stop);
746 if (part->EUNInfo[eun].Free == 0)
749 /* Is this unit's BAM cached? */
750 if (eun != part->bam_index) {
751 /* Invalidate cache */
752 part->bam_index = 0xffff;
754 ret = part->mbd.mtd->read(part->mbd.mtd,
755 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
756 part->BlocksPerUnit * sizeof(u_int32_t),
757 &retlen, (u_char *) (part->bam_cache));
760 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
763 part->bam_index = eun;
766 /* Find a free block */
767 for (blk = 0; blk < part->BlocksPerUnit; blk++)
768 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
769 if (blk == part->BlocksPerUnit) {
775 printk(KERN_NOTICE "ftl_cs: bad free list!\n");
778 DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
784 /*======================================================================
786 Read a series of sectors from an FTL partition.
788 ======================================================================*/
790 static int ftl_read(partition_t *part, caddr_t buffer,
791 u_long sector, u_long nblocks)
793 u_int32_t log_addr, bsize;
796 size_t offset, retlen;
798 DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
799 part, sector, nblocks);
800 if (!(part->state & FTL_FORMATTED)) {
801 printk(KERN_NOTICE "ftl_cs: bad partition\n");
804 bsize = 1 << part->header.EraseUnitSize;
806 for (i = 0; i < nblocks; i++) {
807 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
808 printk(KERN_NOTICE "ftl_cs: bad read offset\n");
811 log_addr = part->VirtualBlockMap[sector+i];
812 if (log_addr == 0xffffffff)
813 memset(buffer, 0, SECTOR_SIZE);
815 offset = (part->EUNInfo[log_addr / bsize].Offset
816 + (log_addr % bsize));
817 ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
818 &retlen, (u_char *) buffer);
821 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
825 buffer += SECTOR_SIZE;
830 /*======================================================================
832 Write a series of sectors to an FTL partition
834 ======================================================================*/
836 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
839 u_int32_t bsize, blk, le_virt_addr;
845 size_t retlen, offset;
847 DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
848 part, log_addr, virt_addr);
849 bsize = 1 << part->header.EraseUnitSize;
850 eun = log_addr / bsize;
851 blk = (log_addr % bsize) / SECTOR_SIZE;
852 offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
853 le32_to_cpu(part->header.BAMOffset));
856 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
857 &retlen, (u_char *)&old_addr);
859 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
862 old_addr = le32_to_cpu(old_addr);
864 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
865 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
866 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
869 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
870 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
871 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
876 le_virt_addr = cpu_to_le32(virt_addr);
877 if (part->bam_index == eun) {
879 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
882 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
884 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
886 le32_to_cpu(part->bam_cache[blk]), old_addr);
891 part->bam_cache[blk] = le_virt_addr;
893 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
894 &retlen, (u_char *)&le_virt_addr);
897 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
898 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
899 log_addr, virt_addr);
902 } /* set_bam_entry */
904 static int ftl_write(partition_t *part, caddr_t buffer,
905 u_long sector, u_long nblocks)
907 u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
910 size_t retlen, offset;
912 DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
913 part, sector, nblocks);
914 if (!(part->state & FTL_FORMATTED)) {
915 printk(KERN_NOTICE "ftl_cs: bad partition\n");
918 /* See if we need to reclaim space, before we start */
919 while (part->FreeTotal < nblocks) {
920 ret = reclaim_block(part);
925 bsize = 1 << part->header.EraseUnitSize;
927 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
928 for (i = 0; i < nblocks; i++) {
929 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
930 printk(KERN_NOTICE "ftl_cs: bad write offset\n");
934 /* Grab a free block */
935 blk = find_free(part);
939 printk(KERN_NOTICE "ftl_cs: internal error: "
940 "no free blocks!\n");
944 /* Tag the BAM entry, and write the new block */
945 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
946 part->EUNInfo[part->bam_index].Free--;
948 if (set_bam_entry(part, log_addr, 0xfffffffe))
950 part->EUNInfo[part->bam_index].Deleted++;
951 offset = (part->EUNInfo[part->bam_index].Offset +
953 ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
957 printk(KERN_NOTICE "ftl_cs: block write failed!\n");
958 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
959 " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
964 /* Only delete the old entry when the new entry is ready */
965 old_addr = part->VirtualBlockMap[sector+i];
966 if (old_addr != 0xffffffff) {
967 part->VirtualBlockMap[sector+i] = 0xffffffff;
968 part->EUNInfo[old_addr/bsize].Deleted++;
969 if (set_bam_entry(part, old_addr, 0))
973 /* Finally, set up the new pointers */
974 if (set_bam_entry(part, log_addr, virt_addr))
976 part->VirtualBlockMap[sector+i] = log_addr;
977 part->EUNInfo[part->bam_index].Deleted--;
979 buffer += SECTOR_SIZE;
980 virt_addr += SECTOR_SIZE;
985 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
987 partition_t *part = (void *)dev;
990 /* Sort of arbitrary: round size down to 4KiB boundary */
991 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
995 geo->cylinders = sect >> 3;
1000 static int ftl_readsect(struct mtd_blktrans_dev *dev,
1001 unsigned long block, char *buf)
1003 return ftl_read((void *)dev, buf, block, 1);
1006 static int ftl_writesect(struct mtd_blktrans_dev *dev,
1007 unsigned long block, char *buf)
1009 return ftl_write((void *)dev, buf, block, 1);
1012 /*====================================================================*/
1014 static void ftl_freepart(partition_t *part)
1016 vfree(part->VirtualBlockMap);
1017 part->VirtualBlockMap = NULL;
1018 kfree(part->VirtualPageMap);
1019 part->VirtualPageMap = NULL;
1020 kfree(part->EUNInfo);
1021 part->EUNInfo = NULL;
1022 kfree(part->XferInfo);
1023 part->XferInfo = NULL;
1024 kfree(part->bam_cache);
1025 part->bam_cache = NULL;
1026 } /* ftl_freepart */
1028 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1030 partition_t *partition;
1032 partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1035 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1040 partition->mbd.mtd = mtd;
1042 if ((scan_header(partition) == 0) &&
1043 (build_maps(partition) == 0)) {
1045 partition->state = FTL_FORMATTED;
1047 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1048 le32_to_cpu(partition->header.FormattedSize) >> 10);
1050 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1052 partition->mbd.tr = tr;
1053 partition->mbd.devnum = -1;
1054 if (!add_mtd_blktrans_dev((void *)partition))
1058 ftl_freepart(partition);
1062 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1064 del_mtd_blktrans_dev(dev);
1065 ftl_freepart((partition_t *)dev);
1069 static struct mtd_blktrans_ops ftl_tr = {
1072 .part_bits = PART_BITS,
1073 .blksize = SECTOR_SIZE,
1074 .readsect = ftl_readsect,
1075 .writesect = ftl_writesect,
1076 .getgeo = ftl_getgeo,
1077 .add_mtd = ftl_add_mtd,
1078 .remove_dev = ftl_remove_dev,
1079 .owner = THIS_MODULE,
1082 static int init_ftl(void)
1084 return register_mtd_blktrans(&ftl_tr);
1087 static void __exit cleanup_ftl(void)
1089 deregister_mtd_blktrans(&ftl_tr);
1092 module_init(init_ftl);
1093 module_exit(cleanup_ftl);
1096 MODULE_LICENSE("Dual MPL/GPL");
1097 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1098 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");