1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2 * $Id: ftl.c,v 1.20 2000/06/23 15:17:53 dwmw2 Exp $
5 /*======================================================================
7 A Flash Translation Layer memory card driver
9 This driver implements a disk-like block device driver with an
10 apparent block size of 512 bytes for flash memory cards.
12 ftl_cs.c 1.62 2000/02/01 00:59:04
14 The contents of this file are subject to the Mozilla Public
15 License Version 1.1 (the "License"); you may not use this file
16 except in compliance with the License. You may obtain a copy of
17 the License at http://www.mozilla.org/MPL/
19 Software distributed under the License is distributed on an "AS
20 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
21 implied. See the License for the specific language governing
22 rights and limitations under the License.
24 The initial developer of the original code is David A. Hinds
25 <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
26 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
28 Alternatively, the contents of this file may be used under the
29 terms of the GNU Public License version 2 (the "GPL"), in which
30 case the provisions of the GPL are applicable instead of the
31 above. If you wish to allow the use of your version of this file
32 only under the terms of the GPL and not to allow others to use
33 your version of this file under the MPL, indicate your decision
34 by deleting the provisions above and replace them with the notice
35 and other provisions required by the GPL. If you do not delete
36 the provisions above, a recipient may use your version of this
37 file under either the MPL or the GPL.
39 LEGAL NOTE: The FTL format is patented by M-Systems. They have
40 granted a license for its use with PCMCIA devices:
42 "M-Systems grants a royalty-free, non-exclusive license under
43 any presently existing M-Systems intellectual property rights
44 necessary for the design and development of FTL-compatible
45 drivers, file systems and utilities using the data formats with
46 PCMCIA PC Cards as described in the PCMCIA Flash Translation
47 Layer (FTL) Specification."
49 Use of the FTL format for non-PCMCIA applications may be an
50 infringement of these patents. For additional information,
51 contact M-Systems (http://www.m-sys.com) directly.
53 ======================================================================*/
56 #define DEBUGLVL debug
59 #include <linux/module.h>
60 #include <linux/mtd/compatmac.h>
61 #include <linux/mtd/mtd.h>
62 /*#define PSYCHO_DEBUG */
64 #include <linux/kernel.h>
65 #include <linux/sched.h>
66 #include <linux/ptrace.h>
67 #include <linux/malloc.h>
68 #include <linux/string.h>
69 #include <linux/timer.h>
70 #include <linux/major.h>
72 #include <linux/ioctl.h>
73 #include <linux/hdreg.h>
76 #if (LINUX_VERSION_CODE >= 0x20100)
77 #include <linux/vmalloc.h>
79 #if (LINUX_VERSION_CODE >= 0x20303)
80 #include <linux/blkpg.h>
83 #include <linux/mtd/ftl.h>
84 /*====================================================================*/
85 /* Stuff which really ought to be in compatmac.h */
87 #if (LINUX_VERSION_CODE < 0x20328)
88 #define register_disk(dev, drive, minors, ops, size) \
89 do { (dev)->part[(drive)*(minors)].nr_sects = size; \
90 if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
91 resetup_one_dev(dev, drive); } while (0);
94 #if (LINUX_VERSION_CODE < 0x20320)
95 #define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn
96 #define blk_init_queue(q, req) q = (req)
97 #define blk_cleanup_queue(q) q = NULL
98 #define request_arg_t void
100 #define request_arg_t request_queue_t *q
104 /*====================================================================*/
106 /* Parameters that can be set with 'insmod' */
108 /* Major device # for FTL device */
109 static int shuffle_freq
= 50;
111 MODULE_PARM(shuffle_freq
, "i");
113 /*====================================================================*/
120 /* Funky stuff for setting up a block device */
121 #define MAJOR_NR FTL_MAJOR
122 #define DEVICE_NAME "ftl"
123 #define DEVICE_REQUEST do_ftl_request
124 #define DEVICE_ON(device)
125 #define DEVICE_OFF(device)
127 #define DEVICE_NR(minor) ((minor)>>5)
128 #define REGION_NR(minor) (((minor)>>3)&3)
129 #define PART_NR(minor) ((minor)&7)
130 #define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part))
132 #include <linux/blk.h>
135 static int debug
= FTL_DEBUG
;
136 MODULE_PARM(debug
, "i");
139 /*====================================================================*/
145 /* Maximum number of separate memory devices we'll allow */
148 /* Maximum number of regions per device */
151 /* Maximum number of partitions in an FTL region */
155 /* Maximum number of outstanding erase requests per socket */
158 /* Sector size -- shouldn't need to change */
159 #define SECTOR_SIZE 512
162 /* Each memory region corresponds to a minor device */
163 typedef struct partition_t
{
164 struct mtd_info
*mtd
;
166 u_int32_t
*VirtualBlockMap
;
167 u_int32_t
*VirtualPageMap
;
171 u_int32_t EraseCount
;
177 u_int32_t EraseCount
;
181 u_int32_t
*bam_cache
;
183 u_int32_t BlocksPerUnit
;
184 erase_unit_header_t header
;
186 region_info_t region
;
187 memory_handle_t handle
;
192 partition_t
*myparts
[MAX_MTD_DEVICES
];
194 static void ftl_notify_add(struct mtd_info
*mtd
);
195 static void ftl_notify_remove(struct mtd_info
*mtd
);
197 void ftl_freepart(partition_t
*part
);
199 static struct mtd_notifier ftl_notifier
={ftl_notify_add
, ftl_notify_remove
, NULL
};
201 /* Partition state flags */
202 #define FTL_FORMATTED 0x01
204 /* Transfer unit states */
205 #define XFER_UNKNOWN 0x00
206 #define XFER_ERASING 0x01
207 #define XFER_ERASED 0x02
208 #define XFER_PREPARED 0x03
209 #define XFER_FAILED 0x04
211 static struct hd_struct ftl_hd
[MINOR_NR(MAX_DEV
, 0, 0)];
212 static int ftl_sizes
[MINOR_NR(MAX_DEV
, 0, 0)];
213 static int ftl_blocksizes
[MINOR_NR(MAX_DEV
, 0, 0)];
215 static struct gendisk ftl_gendisk
= {
218 minor_shift
: PART_BITS
,
220 #if (LINUX_VERSION_CODE < 0x20328)
221 max_nr
: MAX_DEV
*MAX_PART
,
228 /*====================================================================*/
230 static int ftl_ioctl(struct inode
*inode
, struct file
*file
,
231 u_int cmd
, u_long arg
);
232 static int ftl_open(struct inode
*inode
, struct file
*file
);
233 static release_t
ftl_close(struct inode
*inode
, struct file
*file
);
234 static int ftl_reread_partitions(int minor
);
236 static void ftl_erase_callback(struct erase_info
*done
);
238 #if LINUX_VERSION_CODE < 0x20326
239 static struct file_operations ftl_blk_fops
= {
248 static struct block_device_operations ftl_blk_fops
= {
255 /*======================================================================
257 Scan_header() checks to see if a memory region contains an FTL
258 partition. build_maps() reads all the erase unit headers, builds
259 the erase unit map, and then builds the virtual page map.
261 ======================================================================*/
263 static int scan_header(partition_t
*part
)
265 erase_unit_header_t header
;
268 part
->header
.FormattedSize
= 0;
269 /* Search first megabyte for a valid FTL header */
272 offset
+= part
->mtd
->erasesize
?part
->mtd
->erasesize
:0x2000) {
274 ret
= part
->mtd
->read(part
->mtd
, offset
, sizeof(header
), &ret
,
275 (unsigned char *)&header
);
280 if (strcmp(header
.DataOrgTuple
+3, "FTL100") == 0) break;
283 if (offset
== 0x100000) {
284 printk(KERN_NOTICE
"ftl_cs: FTL header not found.\n");
287 if ((le16_to_cpu(header
.NumEraseUnits
) > 65536) || header
.BlockSize
!= 9 ||
288 (header
.EraseUnitSize
< 10) || (header
.EraseUnitSize
> 31) ||
289 (header
.NumTransferUnits
>= le16_to_cpu(header
.NumEraseUnits
))) {
290 printk(KERN_NOTICE
"ftl_cs: FTL header corrupt!\n");
293 if ((1 << header
.EraseUnitSize
) != part
->mtd
->erasesize
) {
294 printk(KERN_NOTICE
"ftl: FTL EraseUnitSize %x != MTD erasesize %lx\n",
295 1 << header
.EraseUnitSize
,part
->mtd
->erasesize
);
298 part
->header
= header
;
302 static int build_maps(partition_t
*part
)
304 erase_unit_header_t header
;
305 u_int16_t xvalid
, xtrans
, i
;
311 /* Set up erase unit maps */
312 part
->DataUnits
= le16_to_cpu(part
->header
.NumEraseUnits
) -
313 part
->header
.NumTransferUnits
;
314 part
->EUNInfo
= kmalloc(part
->DataUnits
* sizeof(struct eun_info_t
),
316 if (!part
->EUNInfo
) return -1;
317 for (i
= 0; i
< part
->DataUnits
; i
++)
318 part
->EUNInfo
[i
].Offset
= 0xffffffff;
320 kmalloc(part
->header
.NumTransferUnits
* sizeof(struct xfer_info_t
),
322 if (!part
->XferInfo
) return -1;
325 for (i
= 0; i
< le16_to_cpu(part
->header
.NumEraseUnits
); i
++) {
326 offset
= ((i
+ le16_to_cpu(part
->header
.FirstPhysicalEUN
))
327 << part
->header
.EraseUnitSize
);
328 ret
= part
->mtd
->read(part
->mtd
, offset
, sizeof(header
), &retval
,
329 (unsigned char *)&header
);
334 /* Is this a transfer partition? */
335 hdr_ok
= (strcmp(header
.DataOrgTuple
+3, "FTL100") == 0);
336 if (hdr_ok
&& (le16_to_cpu(header
.LogicalEUN
) < part
->DataUnits
) &&
337 (part
->EUNInfo
[le16_to_cpu(header
.LogicalEUN
)].Offset
== 0xffffffff)) {
338 part
->EUNInfo
[le16_to_cpu(header
.LogicalEUN
)].Offset
= offset
;
339 part
->EUNInfo
[le16_to_cpu(header
.LogicalEUN
)].EraseCount
=
340 le32_to_cpu(header
.EraseCount
);
343 if (xtrans
== part
->header
.NumTransferUnits
) {
344 printk(KERN_NOTICE
"ftl_cs: format error: too many "
345 "transfer units!\n");
348 if (hdr_ok
&& (le16_to_cpu(header
.LogicalEUN
) == 0xffff)) {
349 part
->XferInfo
[xtrans
].state
= XFER_PREPARED
;
350 part
->XferInfo
[xtrans
].EraseCount
= le32_to_cpu(header
.EraseCount
);
352 part
->XferInfo
[xtrans
].state
= XFER_UNKNOWN
;
353 /* Pick anything reasonable for the erase count */
354 part
->XferInfo
[xtrans
].EraseCount
=
355 le32_to_cpu(part
->header
.EraseCount
);
357 part
->XferInfo
[xtrans
].Offset
= offset
;
361 /* Check for format trouble */
362 header
= part
->header
;
363 if ((xtrans
!= header
.NumTransferUnits
) ||
364 (xvalid
+xtrans
!= le16_to_cpu(header
.NumEraseUnits
))) {
365 printk(KERN_NOTICE
"ftl_cs: format error: erase units "
370 /* Set up virtual page map */
371 blocks
= le32_to_cpu(header
.FormattedSize
) >> header
.BlockSize
;
372 part
->VirtualBlockMap
= vmalloc(blocks
* sizeof(u_int32_t
));
373 memset(part
->VirtualBlockMap
, 0xff, blocks
* sizeof(u_int32_t
));
374 part
->BlocksPerUnit
= (1 << header
.EraseUnitSize
) >> header
.BlockSize
;
376 part
->bam_cache
= kmalloc(part
->BlocksPerUnit
* sizeof(u_int32_t
),
378 if (!part
->bam_cache
) return -1;
380 part
->bam_index
= 0xffff;
383 for (i
= 0; i
< part
->DataUnits
; i
++) {
384 part
->EUNInfo
[i
].Free
= 0;
385 part
->EUNInfo
[i
].Deleted
= 0;
386 offset
= part
->EUNInfo
[i
].Offset
+ le32_to_cpu(header
.BAMOffset
);
388 ret
= part
->mtd
->read(part
->mtd
, offset
,
389 part
->BlocksPerUnit
* sizeof(u_int32_t
), &retval
,
390 (unsigned char *)part
->bam_cache
);
395 for (j
= 0; j
< part
->BlocksPerUnit
; j
++) {
396 if (BLOCK_FREE(le32_to_cpu(part
->bam_cache
[j
]))) {
397 part
->EUNInfo
[i
].Free
++;
399 } else if ((BLOCK_TYPE(le32_to_cpu(part
->bam_cache
[j
])) == BLOCK_DATA
) &&
400 (BLOCK_NUMBER(le32_to_cpu(part
->bam_cache
[j
])) < blocks
))
401 part
->VirtualBlockMap
[BLOCK_NUMBER(le32_to_cpu(part
->bam_cache
[j
]))] =
402 (i
<< header
.EraseUnitSize
) + (j
<< header
.BlockSize
);
403 else if (BLOCK_DELETED(le32_to_cpu(part
->bam_cache
[j
])))
404 part
->EUNInfo
[i
].Deleted
++;
412 /*======================================================================
414 Erase_xfer() schedules an asynchronous erase operation for a
417 ======================================================================*/
419 static int erase_xfer(partition_t
*part
,
423 struct xfer_info_t
*xfer
;
424 struct erase_info
*erase
;
426 xfer
= &part
->XferInfo
[xfernum
];
427 DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer
->Offset
);
428 xfer
->state
= XFER_ERASING
;
430 /* Is there a free erase slot? Always in MTD. */
433 erase
=kmalloc(sizeof(struct erase_info
), GFP_KERNEL
);
437 erase
->callback
= ftl_erase_callback
;
438 erase
->addr
= xfer
->Offset
;
439 erase
->len
= 1 << part
->header
.EraseUnitSize
;
440 erase
->priv
= (u_long
)part
;
442 ret
= part
->mtd
->erase(part
->mtd
, erase
);
452 /*======================================================================
454 Prepare_xfer() takes a freshly erased transfer unit and gives
455 it an appropriate header.
457 ======================================================================*/
459 static void ftl_erase_callback(struct erase_info
*erase
)
462 struct xfer_info_t
*xfer
;
465 /* Look up the transfer unit */
466 part
= (partition_t
*)(erase
->priv
);
468 for (i
= 0; i
< part
->header
.NumTransferUnits
; i
++)
469 if (part
->XferInfo
[i
].Offset
== erase
->addr
) break;
471 if (i
== part
->header
.NumTransferUnits
) {
472 printk(KERN_NOTICE
"ftl_cs: internal error: "
473 "erase lookup failed!\n");
477 xfer
= &part
->XferInfo
[i
];
478 if (erase
->state
== MTD_ERASE_DONE
)
479 xfer
->state
= XFER_ERASED
;
481 xfer
->state
= XFER_FAILED
;
482 printk(KERN_NOTICE
"ftl_cs: erase failed: state = %d\n",
488 } /* ftl_erase_callback */
490 static int prepare_xfer(partition_t
*part
, int i
)
492 erase_unit_header_t header
;
493 struct xfer_info_t
*xfer
;
499 xfer
= &part
->XferInfo
[i
];
500 xfer
->state
= XFER_FAILED
;
502 DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer
->Offset
);
504 /* Write the transfer unit header */
505 header
= part
->header
;
506 header
.LogicalEUN
= cpu_to_le16(0xffff);
507 header
.EraseCount
= cpu_to_le32(xfer
->EraseCount
);
509 ret
= part
->mtd
->write(part
->mtd
, xfer
->Offset
, sizeof(header
),
510 &retlen
, (u_char
*)&header
);
516 /* Write the BAM stub */
517 nbam
= (part
->BlocksPerUnit
* sizeof(u_int32_t
) +
518 le32_to_cpu(part
->header
.BAMOffset
) + SECTOR_SIZE
- 1) / SECTOR_SIZE
;
520 offset
= xfer
->Offset
+ le32_to_cpu(part
->header
.BAMOffset
);
521 ctl
= cpu_to_le32(BLOCK_CONTROL
);
523 for (i
= 0; i
< nbam
; i
++, offset
+= sizeof(u_int32_t
)) {
525 ret
= part
->mtd
->write(part
->mtd
, offset
, sizeof(u_int32_t
),
526 &retlen
, (u_char
*)&ctl
);
531 xfer
->state
= XFER_PREPARED
;
536 /*======================================================================
538 Copy_erase_unit() takes a full erase block and a transfer unit,
539 copies everything to the transfer unit, then swaps the block
542 All data blocks are copied to the corresponding blocks in the
543 target unit, so the virtual block map does not need to be
546 ======================================================================*/
548 static int copy_erase_unit(partition_t
*part
, u_int16_t srcunit
,
551 u_char buf
[SECTOR_SIZE
];
552 struct eun_info_t
*eun
;
553 struct xfer_info_t
*xfer
;
554 u_int32_t src
, dest
, free
, i
;
559 u_int16_t srcunitswap
= cpu_to_le16(srcunit
);
561 eun
= &part
->EUNInfo
[srcunit
];
562 xfer
= &part
->XferInfo
[xferunit
];
563 DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
564 eun
->Offset
, xfer
->Offset
);
567 /* Read current BAM */
568 if (part
->bam_index
!= srcunit
) {
570 offset
= eun
->Offset
+ le32_to_cpu(part
->header
.BAMOffset
);
572 ret
= part
->mtd
->read(part
->mtd
, offset
,
573 part
->BlocksPerUnit
* sizeof(u_int32_t
),
574 &retlen
, (u_char
*) (part
->bam_cache
));
576 /* mark the cache bad, in case we get an error later */
577 part
->bam_index
= 0xffff;
580 printk( KERN_WARNING
"ftl: Failed to read BAM cache in copy_erase_unit()!\n");
585 /* Write the LogicalEUN for the transfer unit */
586 xfer
->state
= XFER_UNKNOWN
;
587 offset
= xfer
->Offset
+ 20; /* Bad! */
588 unit
= cpu_to_le16(0x7fff);
590 ret
= part
->mtd
->write(part
->mtd
, offset
, sizeof(u_int16_t
),
591 &retlen
, (u_char
*) &unit
);
594 printk( KERN_WARNING
"ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
598 /* Copy all data blocks from source unit to transfer unit */
599 src
= eun
->Offset
; dest
= xfer
->Offset
;
603 for (i
= 0; i
< part
->BlocksPerUnit
; i
++) {
604 switch (BLOCK_TYPE(le32_to_cpu(part
->bam_cache
[i
]))) {
606 /* This gets updated later */
609 case BLOCK_REPLACEMENT
:
610 ret
= part
->mtd
->read(part
->mtd
, src
, SECTOR_SIZE
,
611 &retlen
, (u_char
*) buf
);
613 printk(KERN_WARNING
"ftl: Error reading old xfer unit in copy_erase_unit\n");
618 ret
= part
->mtd
->write(part
->mtd
, dest
, SECTOR_SIZE
,
619 &retlen
, (u_char
*) buf
);
621 printk(KERN_WARNING
"ftl: Error writing new xfer unit in copy_erase_unit\n");
627 /* All other blocks must be free */
628 part
->bam_cache
[i
] = cpu_to_le32(0xffffffff);
636 /* Write the BAM to the transfer unit */
637 ret
= part
->mtd
->write(part
->mtd
, xfer
->Offset
+ le32_to_cpu(part
->header
.BAMOffset
),
638 part
->BlocksPerUnit
* sizeof(int32_t), &retlen
,
639 (u_char
*)part
->bam_cache
);
641 printk( KERN_WARNING
"ftl: Error writing BAM in copy_erase_unit\n");
646 /* All clear? Then update the LogicalEUN again */
647 ret
= part
->mtd
->write(part
->mtd
, xfer
->Offset
+ 20, sizeof(u_int16_t
),
648 &retlen
, (u_char
*)&srcunitswap
);
651 printk(KERN_WARNING
"ftl: Error writing new LogicalEUN in copy_erase_unit\n");
656 /* Update the maps and usage stats*/
657 i
= xfer
->EraseCount
;
658 xfer
->EraseCount
= eun
->EraseCount
;
661 xfer
->Offset
= eun
->Offset
;
663 part
->FreeTotal
-= eun
->Free
;
664 part
->FreeTotal
+= free
;
668 /* Now, the cache should be valid for the new block */
669 part
->bam_index
= srcunit
;
672 } /* copy_erase_unit */
674 /*======================================================================
676 reclaim_block() picks a full erase unit and a transfer unit and
677 then calls copy_erase_unit() to copy one to the other. Then, it
678 schedules an erase on the expired block.
680 What's a good way to decide which transfer unit and which erase
681 unit to use? Beats me. My way is to always pick the transfer
682 unit with the fewest erases, and usually pick the data unit with
683 the most deleted blocks. But with a small probability, pick the
684 oldest data unit instead. This means that we generally postpone
685 the next reclaimation as long as possible, but shuffle static
686 stuff around a bit for wear leveling.
688 ======================================================================*/
690 static int reclaim_block(partition_t
*part
)
692 u_int16_t i
, eun
, xfer
;
696 DEBUG(0, "ftl_cs: reclaiming space...\n");
697 DEBUG(4, "NumTransferUnits == %x\n", part
->header
.NumTransferUnits
);
698 /* Pick the least erased transfer unit */
699 best
= 0xffffffff; xfer
= 0xffff;
702 for (i
= 0; i
< part
->header
.NumTransferUnits
; i
++) {
704 if (part
->XferInfo
[i
].state
== XFER_UNKNOWN
) {
705 DEBUG(4,"XferInfo[%d].state == XFER_UNKNOWN\n",i
);
709 if (part
->XferInfo
[i
].state
== XFER_ERASING
) {
710 DEBUG(4,"XferInfo[%d].state == XFER_ERASING\n",i
);
714 else if (part
->XferInfo
[i
].state
== XFER_ERASED
) {
715 DEBUG(4,"XferInfo[%d].state == XFER_ERASED\n",i
);
717 prepare_xfer(part
, i
);
719 if (part
->XferInfo
[i
].state
== XFER_PREPARED
) {
720 DEBUG(4,"XferInfo[%d].state == XFER_PREPARED\n",i
);
722 if (part
->XferInfo
[i
].EraseCount
<= best
) {
723 best
= part
->XferInfo
[i
].EraseCount
;
728 DEBUG(4,"XferInfo[%d].state == %x\n",i
, part
->XferInfo
[i
].state
);
731 if (xfer
== 0xffff) {
733 DEBUG(1, "ftl_cs: waiting for transfer "
734 "unit to be prepared...\n");
736 part
->mtd
->sync(part
->mtd
);
740 printk(KERN_NOTICE
"ftl_cs: reclaim failed: no "
741 "suitable transfer units!\n");
743 DEBUG(1, "ftl_cs: reclaim failed: no "
744 "suitable transfer units!\n");
749 } while (xfer
== 0xffff);
752 if ((jiffies
% shuffle_freq
) == 0) {
753 DEBUG(1, "ftl_cs: recycling freshest block...\n");
755 for (i
= 0; i
< part
->DataUnits
; i
++)
756 if (part
->EUNInfo
[i
].EraseCount
<= best
) {
757 best
= part
->EUNInfo
[i
].EraseCount
;
762 for (i
= 0; i
< part
->DataUnits
; i
++)
763 if (part
->EUNInfo
[i
].Deleted
>= best
) {
764 best
= part
->EUNInfo
[i
].Deleted
;
770 printk(KERN_NOTICE
"ftl_cs: reclaim failed: "
771 "no free blocks!\n");
773 DEBUG(1,"ftl_cs: reclaim failed: "
774 "no free blocks!\n");
779 ret
= copy_erase_unit(part
, eun
, xfer
);
781 erase_xfer(part
, xfer
);
783 printk(KERN_NOTICE
"ftl_cs: copy_erase_unit failed!\n");
785 } /* reclaim_block */
787 /*======================================================================
789 Find_free() searches for a free block. If necessary, it updates
790 the BAM cache for the erase unit containing the free block. It
791 returns the block index -- the erase unit is just the currently
792 cached unit. If there are no free blocks, it returns 0 -- this
793 is never a valid data block because it contains the header.
795 ======================================================================*/
798 static void dump_lists(partition_t
*part
)
801 printk(KERN_DEBUG
"ftl_cs: Free total = %d\n", part
->FreeTotal
);
802 for (i
= 0; i
< part
->DataUnits
; i
++)
803 printk(KERN_DEBUG
"ftl_cs: unit %d: %d phys, %d free, "
805 part
->EUNInfo
[i
].Offset
>> part
->header
.EraseUnitSize
,
806 part
->EUNInfo
[i
].Free
, part
->EUNInfo
[i
].Deleted
);
810 static u_int32_t
find_free(partition_t
*part
)
817 /* Find an erase unit with some free space */
818 stop
= (part
->bam_index
== 0xffff) ? 0 : part
->bam_index
;
821 if (part
->EUNInfo
[eun
].Free
!= 0) break;
822 /* Wrap around at end of table */
823 if (++eun
== part
->DataUnits
) eun
= 0;
824 } while (eun
!= stop
);
826 if (part
->EUNInfo
[eun
].Free
== 0)
829 /* Is this unit's BAM cached? */
830 if (eun
!= part
->bam_index
) {
831 /* Invalidate cache */
832 part
->bam_index
= 0xffff;
834 ret
= part
->mtd
->read(part
->mtd
,
835 part
->EUNInfo
[eun
].Offset
+ le32_to_cpu(part
->header
.BAMOffset
),
836 part
->BlocksPerUnit
* sizeof(u_int32_t
),
837 &retlen
, (u_char
*) (part
->bam_cache
));
840 printk(KERN_WARNING
"ftl: Error reading BAM in find_free\n");
843 part
->bam_index
= eun
;
846 /* Find a free block */
847 for (blk
= 0; blk
< part
->BlocksPerUnit
; blk
++)
848 if (BLOCK_FREE(le32_to_cpu(part
->bam_cache
[blk
]))) break;
849 if (blk
== part
->BlocksPerUnit
) {
855 printk(KERN_NOTICE
"ftl_cs: bad free list!\n");
858 DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk
, eun
);
863 /*======================================================================
865 This gets a memory handle for the region corresponding to the
868 ======================================================================*/
870 static int ftl_open(struct inode
*inode
, struct file
*file
)
872 int minor
= MINOR(inode
->i_rdev
);
873 partition_t
*partition
;
875 if (minor
>>4 >= MAX_MTD_DEVICES
)
878 partition
= myparts
[minor
>>4];
883 if (partition
->state
!= FTL_FORMATTED
)
886 if (ftl_gendisk
.part
[minor
].nr_sects
== 0)
891 if (!get_mtd_device(partition
->mtd
, -1)) {
893 return /* -E'SBUGGEREDOFF */ -ENXIO
;
896 if ((file
->f_mode
& 2) && !(partition
->mtd
->flags
& MTD_CLEAR_BITS
) ) {
897 put_mtd_device(partition
->mtd
);
902 DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor
);
904 atomic_inc(&partition
->open
);
909 /*====================================================================*/
911 static release_t
ftl_close(struct inode
*inode
, struct file
*file
)
913 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
914 struct super_block
*sb
= get_super(inode
->i_rdev
);
916 int minor
= MINOR(inode
->i_rdev
);
917 partition_t
*part
= myparts
[minor
>> 4];
920 DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor
);
922 /* Flush all writes */
923 fsync_dev(inode
->i_rdev
);
924 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
925 if (sb
) invalidate_inodes(sb
);
927 invalidate_buffers(inode
->i_rdev
);
929 /* Wait for any pending erase operations to complete */
931 part
->mtd
->sync(part
->mtd
);
933 for (i
= 0; i
< part
->header
.NumTransferUnits
; i
++) {
934 if (part
->XferInfo
[i
].state
== XFER_ERASED
)
935 prepare_xfer(part
, i
);
938 atomic_dec(&part
->open
);
940 put_mtd_device(part
->mtd
);
946 /*======================================================================
948 Read a series of sectors from an FTL partition.
950 ======================================================================*/
952 static int ftl_read(partition_t
*part
, caddr_t buffer
,
953 u_long sector
, u_long nblocks
)
955 u_int32_t log_addr
, bsize
;
958 size_t offset
, retlen
;
960 DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
961 part
, sector
, nblocks
);
962 if (!(part
->state
& FTL_FORMATTED
)) {
963 printk(KERN_NOTICE
"ftl_cs: bad partition\n");
966 bsize
= 1 << part
->header
.EraseUnitSize
;
968 for (i
= 0; i
< nblocks
; i
++) {
969 if (((sector
+i
) * SECTOR_SIZE
) >= le32_to_cpu(part
->header
.FormattedSize
)) {
970 printk(KERN_NOTICE
"ftl_cs: bad read offset\n");
973 log_addr
= part
->VirtualBlockMap
[sector
+i
];
974 if (log_addr
== 0xffffffff)
975 memset(buffer
, 0, SECTOR_SIZE
);
977 offset
= (part
->EUNInfo
[log_addr
/ bsize
].Offset
978 + (log_addr
% bsize
));
979 ret
= part
->mtd
->read(part
->mtd
, offset
, SECTOR_SIZE
,
980 &retlen
, (u_char
*) buffer
);
983 printk(KERN_WARNING
"Error reading MTD device in ftl_read()\n");
987 buffer
+= SECTOR_SIZE
;
992 /*======================================================================
994 Write a series of sectors to an FTL partition
996 ======================================================================*/
998 static int set_bam_entry(partition_t
*part
, u_int32_t log_addr
,
1001 u_int32_t bsize
, blk
;
1007 size_t retlen
, offset
;
1009 DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
1010 part
, log_addr
, virt_addr
);
1011 bsize
= 1 << part
->header
.EraseUnitSize
;
1012 eun
= log_addr
/ bsize
;
1013 blk
= (log_addr
% bsize
) / SECTOR_SIZE
;
1014 offset
= (part
->EUNInfo
[eun
].Offset
+ blk
* sizeof(u_int32_t
) +
1015 le32_to_cpu(part
->header
.BAMOffset
));
1018 ret
= part
->mtd
->read(part
->mtd
, offset
, sizeof(u_int32_t
),
1019 &retlen
, (u_char
*)&old_addr
);
1021 printk(KERN_WARNING
"ftl: Error reading old_addr in set_bam_entry: %d\n",ret
);
1024 old_addr
= le32_to_cpu(old_addr
);
1026 if (((virt_addr
== 0xfffffffe) && !BLOCK_FREE(old_addr
)) ||
1027 ((virt_addr
== 0) && (BLOCK_TYPE(old_addr
) != BLOCK_DATA
)) ||
1028 (!BLOCK_DELETED(virt_addr
) && (old_addr
!= 0xfffffffe))) {
1031 printk(KERN_NOTICE
"ftl_cs: set_bam_entry() inconsistency!\n");
1032 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, old = 0x%x"
1033 ", new = 0x%x\n", log_addr
, old_addr
, virt_addr
);
1038 if (part
->bam_index
== eun
) {
1040 if (le32_to_cpu(part
->bam_cache
[blk
]) != old_addr
) {
1043 printk(KERN_NOTICE
"ftl_cs: set_bam_entry() "
1044 "inconsistency!\n");
1045 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, cache"
1047 le32_to_cpu(part
->bam_cache
[blk
]), old_addr
);
1052 part
->bam_cache
[blk
] = cpu_to_le32(virt_addr
);
1054 ret
= part
->mtd
->write(part
->mtd
, offset
, sizeof(u_int32_t
),
1055 &retlen
, (u_char
*)&part
->bam_cache
[blk
]);
1058 printk(KERN_NOTICE
"ftl_cs: set_bam_entry() failed!\n");
1059 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, new = 0x%x\n",
1060 log_addr
, virt_addr
);
1063 } /* set_bam_entry */
1065 static int ftl_write(partition_t
*part
, caddr_t buffer
,
1066 u_long sector
, u_long nblocks
)
1068 u_int32_t bsize
, log_addr
, virt_addr
, old_addr
, blk
;
1071 size_t retlen
, offset
;
1073 DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
1074 part
, sector
, nblocks
);
1075 if (!(part
->state
& FTL_FORMATTED
)) {
1076 printk(KERN_NOTICE
"ftl_cs: bad partition\n");
1079 /* See if we need to reclaim space, before we start */
1080 while (part
->FreeTotal
< nblocks
) {
1081 ret
= reclaim_block(part
);
1086 bsize
= 1 << part
->header
.EraseUnitSize
;
1088 virt_addr
= sector
* SECTOR_SIZE
| BLOCK_DATA
;
1089 for (i
= 0; i
< nblocks
; i
++) {
1090 if (virt_addr
>= le32_to_cpu(part
->header
.FormattedSize
)) {
1091 printk(KERN_NOTICE
"ftl_cs: bad write offset\n");
1095 /* Grab a free block */
1096 blk
= find_free(part
);
1100 printk(KERN_NOTICE
"ftl_cs: internal error: "
1101 "no free blocks!\n");
1105 /* Tag the BAM entry, and write the new block */
1106 log_addr
= part
->bam_index
* bsize
+ blk
* SECTOR_SIZE
;
1107 part
->EUNInfo
[part
->bam_index
].Free
--;
1109 if (set_bam_entry(part
, log_addr
, 0xfffffffe))
1111 part
->EUNInfo
[part
->bam_index
].Deleted
++;
1112 offset
= (part
->EUNInfo
[part
->bam_index
].Offset
+
1114 ret
= part
->mtd
->write(part
->mtd
, offset
, SECTOR_SIZE
, &retlen
,
1118 printk(KERN_NOTICE
"ftl_cs: block write failed!\n");
1119 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, virt_addr"
1120 " = 0x%x, Offset = 0x%x\n", log_addr
, virt_addr
,
1125 /* Only delete the old entry when the new entry is ready */
1126 old_addr
= part
->VirtualBlockMap
[sector
+i
];
1127 if (old_addr
!= 0xffffffff) {
1128 part
->VirtualBlockMap
[sector
+i
] = 0xffffffff;
1129 part
->EUNInfo
[old_addr
/bsize
].Deleted
++;
1130 if (set_bam_entry(part
, old_addr
, 0))
1134 /* Finally, set up the new pointers */
1135 if (set_bam_entry(part
, log_addr
, virt_addr
))
1137 part
->VirtualBlockMap
[sector
+i
] = log_addr
;
1138 part
->EUNInfo
[part
->bam_index
].Deleted
--;
1140 buffer
+= SECTOR_SIZE
;
1141 virt_addr
+= SECTOR_SIZE
;
1146 /*======================================================================
1148 IOCTL calls for getting device parameters.
1150 ======================================================================*/
1152 static int ftl_ioctl(struct inode
*inode
, struct file
*file
,
1153 u_int cmd
, u_long arg
)
1155 struct hd_geometry
*geo
= (struct hd_geometry
*)arg
;
1156 int ret
= 0, minor
= MINOR(inode
->i_rdev
);
1157 partition_t
*part
= myparts
[minor
>> 4];
1161 return -ENODEV
; /* How? */
1165 ret
= verify_area(VERIFY_WRITE
, (long *)arg
, sizeof(*geo
));
1166 if (ret
) return ret
;
1167 /* Sort of arbitrary: round size down to 4K boundary */
1168 sect
= le32_to_cpu(part
->header
.FormattedSize
)/SECTOR_SIZE
;
1169 put_user(1, (char *)&geo
->heads
);
1170 put_user(8, (char *)&geo
->sectors
);
1171 put_user((sect
>>3), (short *)&geo
->cylinders
);
1172 put_user(ftl_hd
[minor
].start_sect
, (u_long
*)&geo
->start
);
1175 ret
= verify_area(VERIFY_WRITE
, (long *)arg
, sizeof(long));
1176 if (ret
) return ret
;
1177 put_user(ftl_hd
[minor
].nr_sects
,
1181 ret
= ftl_reread_partitions(minor
);
1183 #if (LINUX_VERSION_CODE < 0x20303)
1185 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
1186 if (!capable(CAP_SYS_ADMIN
)) return -EACCES
;
1188 fsync_dev(inode
->i_rdev
);
1189 invalidate_buffers(inode
->i_rdev
);
1191 RO_IOCTLS(inode
->i_rdev
, arg
);
1196 ret
= blk_ioctl(inode
->i_rdev
, cmd
, arg
);
1206 /*======================================================================
1208 Handler for block device requests
1210 ======================================================================*/
1212 static int ftl_reread_partitions(int minor
)
1214 partition_t
*part
= myparts
[minor
>> 4];
1217 DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor
);
1218 if ((atomic_read(&part
->open
) > 1)) {
1221 whole
= minor
& ~(MAX_PART
-1);
1223 for (i
= 0; i
< MAX_PART
; i
++) {
1224 if (ftl_hd
[whole
+i
].nr_sects
> 0) {
1225 kdev_t rdev
= MKDEV(FTL_MAJOR
, whole
+i
);
1227 invalidate_buffers(rdev
);
1229 ftl_hd
[whole
+i
].start_sect
= 0;
1230 ftl_hd
[whole
+i
].nr_sects
= 0;
1235 register_disk(&ftl_gendisk
, whole
>> PART_BITS
, MAX_PART
,
1236 &ftl_blk_fops
, le32_to_cpu(part
->header
.FormattedSize
)/SECTOR_SIZE
);
1239 for (i
= 0; i
< MAX_PART
; i
++) {
1240 if (ftl_hd
[whole
+i
].nr_sects
> 0)
1241 printk(KERN_INFO
" %d: start %ld size %ld\n", i
,
1242 ftl_hd
[whole
+i
].start_sect
,
1243 ftl_hd
[whole
+i
].nr_sects
);
1249 /*======================================================================
1251 Handler for block device requests
1253 ======================================================================*/
1255 static void do_ftl_request(request_arg_t
)
1264 minor
= MINOR(CURRENT
->rq_dev
);
1266 part
= myparts
[minor
>> 4];
1270 switch (CURRENT
->cmd
) {
1272 ret
= ftl_read(part
, CURRENT
->buffer
,
1273 CURRENT
->sector
+ftl_hd
[minor
].start_sect
,
1274 CURRENT
->current_nr_sectors
);
1275 if (ret
) printk("ftl_read returned %d\n", ret
);
1279 ret
= ftl_write(part
, CURRENT
->buffer
,
1280 CURRENT
->sector
+ftl_hd
[minor
].start_sect
,
1281 CURRENT
->current_nr_sectors
);
1282 if (ret
) printk("ftl_write returned %d\n", ret
);
1286 panic("ftl_cs: unknown block command!\n");
1291 printk("NULL part in ftl_request\n");
1295 CURRENT
->sector
+= CURRENT
->current_nr_sectors
;
1298 end_request((ret
== 0) ? 1 : 0);
1300 } /* do_ftl_request */
1302 /*====================================================================*/
1304 void ftl_freepart(partition_t
*part
)
1306 if (part
->VirtualBlockMap
) {
1307 vfree(part
->VirtualBlockMap
);
1308 part
->VirtualBlockMap
= NULL
;
1310 if (part
->VirtualPageMap
) {
1311 kfree(part
->VirtualPageMap
);
1312 part
->VirtualPageMap
= NULL
;
1314 if (part
->EUNInfo
) {
1315 kfree(part
->EUNInfo
);
1316 part
->EUNInfo
= NULL
;
1318 if (part
->XferInfo
) {
1319 kfree(part
->XferInfo
);
1320 part
->XferInfo
= NULL
;
1322 if (part
->bam_cache
) {
1323 kfree(part
->bam_cache
);
1324 part
->bam_cache
= NULL
;
1327 } /* ftl_freepart */
1329 static void ftl_notify_add(struct mtd_info
*mtd
)
1331 partition_t
*partition
;
1334 for (device
=0; device
< MAX_MTD_DEVICES
&& myparts
[device
]; device
++)
1337 if (device
== MAX_MTD_DEVICES
) {
1338 printk(KERN_NOTICE
"Maximum number of FTL partitions reached\n"
1339 "Not scanning <%s>\n", mtd
->name
);
1343 partition
= kmalloc(sizeof(partition_t
), GFP_KERNEL
);
1346 printk(KERN_WARNING
"No memory to scan for FTL on %s\n",
1351 memset(partition
, 0, sizeof(partition_t
));
1353 partition
->mtd
= mtd
;
1355 if ((scan_header(partition
) == 0) &&
1356 (build_maps(partition
) == 0)) {
1358 partition
->state
= FTL_FORMATTED
;
1359 atomic_set(&partition
->open
, 0);
1360 myparts
[device
] = partition
;
1361 ftl_reread_partitions(device
<< 4);
1363 printk(KERN_INFO
"ftl_cs: opening %d kb FTL partition\n",
1364 le32_to_cpu(partition
->header
.FormattedSize
) >> 10);
1369 static void ftl_notify_remove(struct mtd_info
*mtd
)
1373 /* Q: What happens if you try to remove a device which has
1374 * a currently-open FTL partition on it?
1376 * A: You don't. The ftl_open routine is responsible for
1377 * increasing the use count of the driver module which
1381 /* That's the theory, anyway :) */
1383 for (i
=0; i
< MAX_MTD_DEVICES
; i
++)
1384 if (myparts
[i
] && myparts
[i
]->mtd
== mtd
) {
1386 if (myparts
[i
]->state
== FTL_FORMATTED
)
1387 ftl_freepart(myparts
[i
]);
1389 myparts
[i
]->state
= 0;
1390 for (j
=0; j
<16; j
++) {
1391 ftl_gendisk
.part
[j
].nr_sects
=0;
1392 ftl_gendisk
.part
[j
].start_sect
=0;
1400 #if LINUX_VERSION_CODE < 0x20300
1402 #define init_ftl init_module
1403 #define cleanup_ftl cleanup_module
1407 mod_init_t
init_ftl(void)
1411 memset(myparts
, 0, sizeof(myparts
));
1413 DEBUG(0, "$Id: ftl.c,v 1.20 2000/06/23 15:17:53 dwmw2 Exp $\n");
1415 if (register_blkdev(FTL_MAJOR
, "ftl", &ftl_blk_fops
)) {
1416 printk(KERN_NOTICE
"ftl_cs: unable to grab major "
1417 "device number!\n");
1421 for (i
= 0; i
< MINOR_NR(MAX_DEV
, 0, 0); i
++)
1422 ftl_blocksizes
[i
] = 1024;
1423 for (i
= 0; i
< MAX_DEV
*MAX_PART
; i
++) {
1424 ftl_hd
[i
].nr_sects
= 0;
1425 ftl_hd
[i
].start_sect
= 0;
1427 blksize_size
[FTL_MAJOR
] = ftl_blocksizes
;
1428 ftl_gendisk
.major
= FTL_MAJOR
;
1429 blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR
), &do_ftl_request
);
1430 ftl_gendisk
.next
= gendisk_head
;
1431 gendisk_head
= &ftl_gendisk
;
1433 register_mtd_user(&ftl_notifier
);
1438 mod_exit_t
cleanup_ftl(void)
1440 struct gendisk
*gd
, **gdp
;
1442 unregister_mtd_user(&ftl_notifier
);
1444 unregister_blkdev(FTL_MAJOR
, "ftl");
1445 blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR
));
1446 blksize_size
[FTL_MAJOR
] = NULL
;
1448 for (gdp
= &gendisk_head
; *gdp
; gdp
= &((*gdp
)->next
))
1449 if (*gdp
== &ftl_gendisk
) {
1450 gd
= *gdp
; *gdp
= gd
->next
;
1455 #if LINUX_VERSION_CODE > 0x20300
1456 module_init(init_ftl
);
1457 module_exit(cleanup_ftl
);