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
29 are Copyright © 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 directly. M-Systems since acquired by Sandisk.
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 <linux/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 uint32_t *VirtualBlockMap;
129 uint32_t BlocksPerUnit;
130 erase_unit_header_t header;
133 /* Partition state flags */
134 #define FTL_FORMATTED 0x01
136 /* Transfer unit states */
137 #define XFER_UNKNOWN 0x00
138 #define XFER_ERASING 0x01
139 #define XFER_ERASED 0x02
140 #define XFER_PREPARED 0x03
141 #define XFER_FAILED 0x04
143 /*======================================================================
145 Scan_header() checks to see if a memory region contains an FTL
146 partition. build_maps() reads all the erase unit headers, builds
147 the erase unit map, and then builds the virtual page map.
149 ======================================================================*/
151 static int scan_header(partition_t *part)
153 erase_unit_header_t header;
154 loff_t offset, max_offset;
157 part->header.FormattedSize = 0;
158 max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
159 /* Search first megabyte for a valid FTL header */
161 (offset + sizeof(header)) < max_offset;
162 offset += part->mbd.mtd->erasesize ? : 0x2000) {
164 err = mtd_read(part->mbd.mtd, offset, sizeof(header), &ret,
165 (unsigned char *)&header);
170 if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
173 if (offset == max_offset) {
174 printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
177 if (header.BlockSize != 9 ||
178 (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
179 (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
180 printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
183 if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
184 printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
185 1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
188 part->header = header;
192 static int build_maps(partition_t *part)
194 erase_unit_header_t header;
195 uint16_t xvalid, xtrans, i;
197 int hdr_ok, ret = -1;
201 /* Set up erase unit maps */
202 part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
203 part->header.NumTransferUnits;
204 part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
208 for (i = 0; i < part->DataUnits; i++)
209 part->EUNInfo[i].Offset = 0xffffffff;
211 kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
217 for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
218 offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
219 << part->header.EraseUnitSize);
220 ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval,
221 (unsigned char *)&header);
227 /* Is this a transfer partition? */
228 hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
229 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
230 (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
231 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
232 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
233 le32_to_cpu(header.EraseCount);
236 if (xtrans == part->header.NumTransferUnits) {
237 printk(KERN_NOTICE "ftl_cs: format error: too many "
238 "transfer units!\n");
241 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
242 part->XferInfo[xtrans].state = XFER_PREPARED;
243 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
245 part->XferInfo[xtrans].state = XFER_UNKNOWN;
246 /* Pick anything reasonable for the erase count */
247 part->XferInfo[xtrans].EraseCount =
248 le32_to_cpu(part->header.EraseCount);
250 part->XferInfo[xtrans].Offset = offset;
254 /* Check for format trouble */
255 header = part->header;
256 if ((xtrans != header.NumTransferUnits) ||
257 (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
258 printk(KERN_NOTICE "ftl_cs: format error: erase units "
263 /* Set up virtual page map */
264 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
265 part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t));
266 if (!part->VirtualBlockMap)
269 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
270 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
272 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t),
274 if (!part->bam_cache)
275 goto out_VirtualBlockMap;
277 part->bam_index = 0xffff;
280 for (i = 0; i < part->DataUnits; i++) {
281 part->EUNInfo[i].Free = 0;
282 part->EUNInfo[i].Deleted = 0;
283 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
285 ret = mtd_read(part->mbd.mtd, offset,
286 part->BlocksPerUnit * sizeof(uint32_t), &retval,
287 (unsigned char *)part->bam_cache);
292 for (j = 0; j < part->BlocksPerUnit; j++) {
293 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
294 part->EUNInfo[i].Free++;
296 } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
297 (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
298 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
299 (i << header.EraseUnitSize) + (j << header.BlockSize);
300 else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
301 part->EUNInfo[i].Deleted++;
309 kfree(part->bam_cache);
311 vfree(part->VirtualBlockMap);
313 kfree(part->XferInfo);
315 kfree(part->EUNInfo);
320 /*======================================================================
322 Erase_xfer() schedules an asynchronous erase operation for a
325 ======================================================================*/
327 static int erase_xfer(partition_t *part,
331 struct xfer_info_t *xfer;
332 struct erase_info *erase;
334 xfer = &part->XferInfo[xfernum];
335 pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
336 xfer->state = XFER_ERASING;
338 /* Is there a free erase slot? Always in MTD. */
341 erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
345 erase->addr = xfer->Offset;
346 erase->len = 1 << part->header.EraseUnitSize;
348 ret = mtd_erase(part->mbd.mtd, erase);
350 xfer->state = XFER_ERASED;
353 xfer->state = XFER_FAILED;
354 pr_notice("ftl_cs: erase failed: err = %d\n", ret);
362 /*======================================================================
364 Prepare_xfer() takes a freshly erased transfer unit and gives
365 it an appropriate header.
367 ======================================================================*/
369 static int prepare_xfer(partition_t *part, int i)
371 erase_unit_header_t header;
372 struct xfer_info_t *xfer;
378 xfer = &part->XferInfo[i];
379 xfer->state = XFER_FAILED;
381 pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
383 /* Write the transfer unit header */
384 header = part->header;
385 header.LogicalEUN = cpu_to_le16(0xffff);
386 header.EraseCount = cpu_to_le32(xfer->EraseCount);
388 ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen,
395 /* Write the BAM stub */
396 nbam = DIV_ROUND_UP(part->BlocksPerUnit * sizeof(uint32_t) +
397 le32_to_cpu(part->header.BAMOffset), SECTOR_SIZE);
399 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
400 ctl = cpu_to_le32(BLOCK_CONTROL);
402 for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
404 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
410 xfer->state = XFER_PREPARED;
415 /*======================================================================
417 Copy_erase_unit() takes a full erase block and a transfer unit,
418 copies everything to the transfer unit, then swaps the block
421 All data blocks are copied to the corresponding blocks in the
422 target unit, so the virtual block map does not need to be
425 ======================================================================*/
427 static int copy_erase_unit(partition_t *part, uint16_t srcunit,
430 u_char buf[SECTOR_SIZE];
431 struct eun_info_t *eun;
432 struct xfer_info_t *xfer;
433 uint32_t src, dest, free, i;
438 uint16_t srcunitswap = cpu_to_le16(srcunit);
440 eun = &part->EUNInfo[srcunit];
441 xfer = &part->XferInfo[xferunit];
442 pr_debug("ftl_cs: copying block 0x%x to 0x%x\n",
443 eun->Offset, xfer->Offset);
446 /* Read current BAM */
447 if (part->bam_index != srcunit) {
449 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
451 ret = mtd_read(part->mbd.mtd, offset,
452 part->BlocksPerUnit * sizeof(uint32_t), &retlen,
453 (u_char *)(part->bam_cache));
455 /* mark the cache bad, in case we get an error later */
456 part->bam_index = 0xffff;
459 printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
464 /* Write the LogicalEUN for the transfer unit */
465 xfer->state = XFER_UNKNOWN;
466 offset = xfer->Offset + 20; /* Bad! */
467 unit = cpu_to_le16(0x7fff);
469 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen,
473 printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
477 /* Copy all data blocks from source unit to transfer unit */
478 src = eun->Offset; dest = xfer->Offset;
482 for (i = 0; i < part->BlocksPerUnit; i++) {
483 switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
485 /* This gets updated later */
488 case BLOCK_REPLACEMENT:
489 ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen,
492 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
497 ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen,
500 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
506 /* All other blocks must be free */
507 part->bam_cache[i] = cpu_to_le32(0xffffffff);
515 /* Write the BAM to the transfer unit */
516 ret = mtd_write(part->mbd.mtd,
517 xfer->Offset + le32_to_cpu(part->header.BAMOffset),
518 part->BlocksPerUnit * sizeof(int32_t),
520 (u_char *)part->bam_cache);
522 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
527 /* All clear? Then update the LogicalEUN again */
528 ret = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
529 &retlen, (u_char *)&srcunitswap);
532 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
537 /* Update the maps and usage stats*/
538 swap(xfer->EraseCount, eun->EraseCount);
539 swap(xfer->Offset, eun->Offset);
540 part->FreeTotal -= eun->Free;
541 part->FreeTotal += free;
545 /* Now, the cache should be valid for the new block */
546 part->bam_index = srcunit;
549 } /* copy_erase_unit */
551 /*======================================================================
553 reclaim_block() picks a full erase unit and a transfer unit and
554 then calls copy_erase_unit() to copy one to the other. Then, it
555 schedules an erase on the expired block.
557 What's a good way to decide which transfer unit and which erase
558 unit to use? Beats me. My way is to always pick the transfer
559 unit with the fewest erases, and usually pick the data unit with
560 the most deleted blocks. But with a small probability, pick the
561 oldest data unit instead. This means that we generally postpone
562 the next reclamation as long as possible, but shuffle static
563 stuff around a bit for wear leveling.
565 ======================================================================*/
567 static int reclaim_block(partition_t *part)
569 uint16_t i, eun, xfer;
573 pr_debug("ftl_cs: reclaiming space...\n");
574 pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits);
575 /* Pick the least erased transfer unit */
576 best = 0xffffffff; xfer = 0xffff;
579 for (i = 0; i < part->header.NumTransferUnits; i++) {
581 if (part->XferInfo[i].state == XFER_UNKNOWN) {
582 pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i);
586 if (part->XferInfo[i].state == XFER_ERASING) {
587 pr_debug("XferInfo[%d].state == XFER_ERASING\n",i);
591 else if (part->XferInfo[i].state == XFER_ERASED) {
592 pr_debug("XferInfo[%d].state == XFER_ERASED\n",i);
594 prepare_xfer(part, i);
596 if (part->XferInfo[i].state == XFER_PREPARED) {
597 pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i);
599 if (part->XferInfo[i].EraseCount <= best) {
600 best = part->XferInfo[i].EraseCount;
605 pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
608 if (xfer == 0xffff) {
610 pr_debug("ftl_cs: waiting for transfer "
611 "unit to be prepared...\n");
612 mtd_sync(part->mbd.mtd);
616 printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
617 "suitable transfer units!\n");
619 pr_debug("ftl_cs: reclaim failed: no "
620 "suitable transfer units!\n");
625 } while (xfer == 0xffff);
628 if ((jiffies % shuffle_freq) == 0) {
629 pr_debug("ftl_cs: recycling freshest block...\n");
631 for (i = 0; i < part->DataUnits; i++)
632 if (part->EUNInfo[i].EraseCount <= best) {
633 best = part->EUNInfo[i].EraseCount;
638 for (i = 0; i < part->DataUnits; i++)
639 if (part->EUNInfo[i].Deleted >= best) {
640 best = part->EUNInfo[i].Deleted;
646 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
647 "no free blocks!\n");
649 pr_debug("ftl_cs: reclaim failed: "
650 "no free blocks!\n");
655 ret = copy_erase_unit(part, eun, xfer);
657 erase_xfer(part, xfer);
659 printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
661 } /* reclaim_block */
663 /*======================================================================
665 Find_free() searches for a free block. If necessary, it updates
666 the BAM cache for the erase unit containing the free block. It
667 returns the block index -- the erase unit is just the currently
668 cached unit. If there are no free blocks, it returns 0 -- this
669 is never a valid data block because it contains the header.
671 ======================================================================*/
674 static void dump_lists(partition_t *part)
677 printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
678 for (i = 0; i < part->DataUnits; i++)
679 printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
681 part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
682 part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
686 static uint32_t find_free(partition_t *part)
693 /* Find an erase unit with some free space */
694 stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
697 if (part->EUNInfo[eun].Free != 0) break;
698 /* Wrap around at end of table */
699 if (++eun == part->DataUnits) eun = 0;
700 } while (eun != stop);
702 if (part->EUNInfo[eun].Free == 0)
705 /* Is this unit's BAM cached? */
706 if (eun != part->bam_index) {
707 /* Invalidate cache */
708 part->bam_index = 0xffff;
710 ret = mtd_read(part->mbd.mtd,
711 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
712 part->BlocksPerUnit * sizeof(uint32_t),
714 (u_char *)(part->bam_cache));
717 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
720 part->bam_index = eun;
723 /* Find a free block */
724 for (blk = 0; blk < part->BlocksPerUnit; blk++)
725 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
726 if (blk == part->BlocksPerUnit) {
732 printk(KERN_NOTICE "ftl_cs: bad free list!\n");
735 pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun);
741 /*======================================================================
743 Read a series of sectors from an FTL partition.
745 ======================================================================*/
747 static int ftl_read(partition_t *part, caddr_t buffer,
748 u_long sector, u_long nblocks)
750 uint32_t log_addr, bsize;
753 size_t offset, retlen;
755 pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
756 part, sector, nblocks);
757 if (!(part->state & FTL_FORMATTED)) {
758 printk(KERN_NOTICE "ftl_cs: bad partition\n");
761 bsize = 1 << part->header.EraseUnitSize;
763 for (i = 0; i < nblocks; i++) {
764 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
765 printk(KERN_NOTICE "ftl_cs: bad read offset\n");
768 log_addr = part->VirtualBlockMap[sector+i];
769 if (log_addr == 0xffffffff)
770 memset(buffer, 0, SECTOR_SIZE);
772 offset = (part->EUNInfo[log_addr / bsize].Offset
773 + (log_addr % bsize));
774 ret = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
778 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
782 buffer += SECTOR_SIZE;
787 /*======================================================================
789 Write a series of sectors to an FTL partition
791 ======================================================================*/
793 static int set_bam_entry(partition_t *part, uint32_t log_addr,
796 uint32_t bsize, blk, le_virt_addr;
802 size_t retlen, offset;
804 pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
805 part, log_addr, virt_addr);
806 bsize = 1 << part->header.EraseUnitSize;
807 eun = log_addr / bsize;
808 blk = (log_addr % bsize) / SECTOR_SIZE;
809 offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
810 le32_to_cpu(part->header.BAMOffset));
813 ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
814 (u_char *)&old_addr);
816 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
819 old_addr = le32_to_cpu(old_addr);
821 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
822 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
823 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
826 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
827 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
828 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
833 le_virt_addr = cpu_to_le32(virt_addr);
834 if (part->bam_index == eun) {
836 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
839 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
841 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
843 le32_to_cpu(part->bam_cache[blk]), old_addr);
848 part->bam_cache[blk] = le_virt_addr;
850 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
851 (u_char *)&le_virt_addr);
854 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
855 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
856 log_addr, virt_addr);
859 } /* set_bam_entry */
861 static int ftl_write(partition_t *part, caddr_t buffer,
862 u_long sector, u_long nblocks)
864 uint32_t bsize, log_addr, virt_addr, old_addr, blk;
867 size_t retlen, offset;
869 pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
870 part, sector, nblocks);
871 if (!(part->state & FTL_FORMATTED)) {
872 printk(KERN_NOTICE "ftl_cs: bad partition\n");
875 /* See if we need to reclaim space, before we start */
876 while (part->FreeTotal < nblocks) {
877 ret = reclaim_block(part);
882 bsize = 1 << part->header.EraseUnitSize;
884 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
885 for (i = 0; i < nblocks; i++) {
886 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
887 printk(KERN_NOTICE "ftl_cs: bad write offset\n");
891 /* Grab a free block */
892 blk = find_free(part);
896 printk(KERN_NOTICE "ftl_cs: internal error: "
897 "no free blocks!\n");
901 /* Tag the BAM entry, and write the new block */
902 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
903 part->EUNInfo[part->bam_index].Free--;
905 if (set_bam_entry(part, log_addr, 0xfffffffe))
907 part->EUNInfo[part->bam_index].Deleted++;
908 offset = (part->EUNInfo[part->bam_index].Offset +
910 ret = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer);
913 printk(KERN_NOTICE "ftl_cs: block write failed!\n");
914 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
915 " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
920 /* Only delete the old entry when the new entry is ready */
921 old_addr = part->VirtualBlockMap[sector+i];
922 if (old_addr != 0xffffffff) {
923 part->VirtualBlockMap[sector+i] = 0xffffffff;
924 part->EUNInfo[old_addr/bsize].Deleted++;
925 if (set_bam_entry(part, old_addr, 0))
929 /* Finally, set up the new pointers */
930 if (set_bam_entry(part, log_addr, virt_addr))
932 part->VirtualBlockMap[sector+i] = log_addr;
933 part->EUNInfo[part->bam_index].Deleted--;
935 buffer += SECTOR_SIZE;
936 virt_addr += SECTOR_SIZE;
941 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
943 partition_t *part = (void *)dev;
946 /* Sort of arbitrary: round size down to 4KiB boundary */
947 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
951 geo->cylinders = sect >> 3;
956 static int ftl_readsect(struct mtd_blktrans_dev *dev,
957 unsigned long block, char *buf)
959 return ftl_read((void *)dev, buf, block, 1);
962 static int ftl_writesect(struct mtd_blktrans_dev *dev,
963 unsigned long block, char *buf)
965 return ftl_write((void *)dev, buf, block, 1);
968 static int ftl_discardsect(struct mtd_blktrans_dev *dev,
969 unsigned long sector, unsigned nr_sects)
971 partition_t *part = (void *)dev;
972 uint32_t bsize = 1 << part->header.EraseUnitSize;
974 pr_debug("FTL erase sector %ld for %d sectors\n",
978 uint32_t old_addr = part->VirtualBlockMap[sector];
979 if (old_addr != 0xffffffff) {
980 part->VirtualBlockMap[sector] = 0xffffffff;
981 part->EUNInfo[old_addr/bsize].Deleted++;
982 if (set_bam_entry(part, old_addr, 0))
991 /*====================================================================*/
993 static void ftl_freepart(partition_t *part)
995 vfree(part->VirtualBlockMap);
996 part->VirtualBlockMap = NULL;
997 kfree(part->EUNInfo);
998 part->EUNInfo = NULL;
999 kfree(part->XferInfo);
1000 part->XferInfo = NULL;
1001 kfree(part->bam_cache);
1002 part->bam_cache = NULL;
1003 } /* ftl_freepart */
1005 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1007 partition_t *partition;
1009 partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1012 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1017 partition->mbd.mtd = mtd;
1019 if ((scan_header(partition) == 0) &&
1020 (build_maps(partition) == 0)) {
1022 partition->state = FTL_FORMATTED;
1024 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1025 le32_to_cpu(partition->header.FormattedSize) >> 10);
1027 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1029 partition->mbd.tr = tr;
1030 partition->mbd.devnum = -1;
1031 if (!add_mtd_blktrans_dev((void *)partition))
1038 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1040 del_mtd_blktrans_dev(dev);
1041 ftl_freepart((partition_t *)dev);
1044 static struct mtd_blktrans_ops ftl_tr = {
1047 .part_bits = PART_BITS,
1048 .blksize = SECTOR_SIZE,
1049 .readsect = ftl_readsect,
1050 .writesect = ftl_writesect,
1051 .discard = ftl_discardsect,
1052 .getgeo = ftl_getgeo,
1053 .add_mtd = ftl_add_mtd,
1054 .remove_dev = ftl_remove_dev,
1055 .owner = THIS_MODULE,
1058 static int __init init_ftl(void)
1060 return register_mtd_blktrans(&ftl_tr);
1063 static void __exit cleanup_ftl(void)
1065 deregister_mtd_blktrans(&ftl_tr);
1068 module_init(init_ftl);
1069 module_exit(cleanup_ftl);
1072 MODULE_LICENSE("Dual MPL/GPL");
1074 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");