1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2 * $Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $
4 * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
5 * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
9 /*======================================================================
11 A Flash Translation Layer memory card driver
13 This driver implements a disk-like block device driver with an
14 apparent block size of 512 bytes for flash memory cards.
16 ftl_cs.c 1.62 2000/02/01 00:59:04
18 The contents of this file are subject to the Mozilla Public
19 License Version 1.1 (the "License"); you may not use this file
20 except in compliance with the License. You may obtain a copy of
21 the License at http://www.mozilla.org/MPL/
23 Software distributed under the License is distributed on an "AS
24 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
25 implied. See the License for the specific language governing
26 rights and limitations under the License.
28 The initial developer of the original code is David A. Hinds
29 <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
30 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
32 Alternatively, the contents of this file may be used under the
33 terms of the GNU General Public License version 2 (the "GPL"), in
34 which case the provisions of the GPL are applicable instead of the
35 above. If you wish to allow the use of your version of this file
36 only under the terms of the GPL and not to allow others to use
37 your version of this file under the MPL, indicate your decision
38 by deleting the provisions above and replace them with the notice
39 and other provisions required by the GPL. If you do not delete
40 the provisions above, a recipient may use your version of this
41 file under either the MPL or the GPL.
43 LEGAL NOTE: The FTL format is patented by M-Systems. They have
44 granted a license for its use with PCMCIA devices:
46 "M-Systems grants a royalty-free, non-exclusive license under
47 any presently existing M-Systems intellectual property rights
48 necessary for the design and development of FTL-compatible
49 drivers, file systems and utilities using the data formats with
50 PCMCIA PC Cards as described in the PCMCIA Flash Translation
51 Layer (FTL) Specification."
53 Use of the FTL format for non-PCMCIA applications may be an
54 infringement of these patents. For additional information,
55 contact M-Systems (http://www.m-sys.com) directly.
57 ======================================================================*/
58 #include <linux/module.h>
59 #include <linux/mtd/compatmac.h>
60 #include <linux/mtd/mtd.h>
61 /*#define PSYCHO_DEBUG */
63 #include <linux/kernel.h>
64 #include <linux/sched.h>
65 #include <linux/ptrace.h>
66 #include <linux/slab.h>
67 #include <linux/string.h>
68 #include <linux/timer.h>
69 #include <linux/major.h>
71 #include <linux/ioctl.h>
72 #include <linux/hdreg.h>
75 #include <linux/vmalloc.h>
76 #include <linux/blkpg.h>
78 #include <linux/mtd/ftl.h>
80 #define request_arg_t request_queue_t *q
82 /*====================================================================*/
84 /* Parameters that can be set with 'insmod' */
85 static int shuffle_freq
= 50;
86 MODULE_PARM(shuffle_freq
, "i");
88 /*====================================================================*/
90 /* Major device # for FTL device */
95 /* Funky stuff for setting up a block device */
96 #define MAJOR_NR FTL_MAJOR
97 #define DEVICE_NAME "ftl"
98 #define DEVICE_OFF(device)
100 #define DEVICE_NR(minor) ((minor)>>5)
101 #define REGION_NR(minor) (((minor)>>3)&3)
102 #define PART_NR(minor) ((minor)&7)
103 #define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part))
105 #include <linux/blk.h>
107 /*====================================================================*/
109 /* Maximum number of separate memory devices we'll allow */
112 /* Maximum number of regions per device */
115 /* Maximum number of partitions in an FTL region */
119 /* Maximum number of outstanding erase requests per socket */
122 /* Sector size -- shouldn't need to change */
123 #define SECTOR_SIZE 512
126 /* Each memory region corresponds to a minor device */
127 typedef struct partition_t
{
128 struct mtd_info
*mtd
;
130 u_int32_t
*VirtualBlockMap
;
131 u_int32_t
*VirtualPageMap
;
135 u_int32_t EraseCount
;
141 u_int32_t EraseCount
;
145 u_int32_t
*bam_cache
;
147 u_int32_t BlocksPerUnit
;
148 erase_unit_header_t header
;
150 region_info_t region
;
151 memory_handle_t handle
;
156 partition_t
*myparts
[MAX_MTD_DEVICES
];
158 static void ftl_notify_add(struct mtd_info
*mtd
);
159 static void ftl_notify_remove(struct mtd_info
*mtd
);
161 void ftl_freepart(partition_t
*part
);
163 static struct mtd_notifier ftl_notifier
= {
165 remove
: ftl_notify_remove
,
168 /* Partition state flags */
169 #define FTL_FORMATTED 0x01
171 /* Transfer unit states */
172 #define XFER_UNKNOWN 0x00
173 #define XFER_ERASING 0x01
174 #define XFER_ERASED 0x02
175 #define XFER_PREPARED 0x03
176 #define XFER_FAILED 0x04
178 static struct hd_struct ftl_hd
[MINOR_NR(MAX_DEV
, 0, 0)];
179 static int ftl_sizes
[MINOR_NR(MAX_DEV
, 0, 0)];
181 static struct gendisk ftl_gendisk
= {
184 minor_shift
: PART_BITS
,
189 /*====================================================================*/
191 static int ftl_ioctl(struct inode
*inode
, struct file
*file
,
192 u_int cmd
, u_long arg
);
193 static int ftl_open(struct inode
*inode
, struct file
*file
);
194 static release_t
ftl_close(struct inode
*inode
, struct file
*file
);
195 static int ftl_reread_partitions(kdev_t dev
);
197 static void ftl_erase_callback(struct erase_info
*done
);
199 static struct block_device_operations ftl_blk_fops
= {
206 /*======================================================================
208 Scan_header() checks to see if a memory region contains an FTL
209 partition. build_maps() reads all the erase unit headers, builds
210 the erase unit map, and then builds the virtual page map.
212 ======================================================================*/
214 static int scan_header(partition_t
*part
)
216 erase_unit_header_t header
;
217 loff_t offset
, max_offset
;
219 part
->header
.FormattedSize
= 0;
220 max_offset
= (0x100000<part
->mtd
->size
)?0x100000:part
->mtd
->size
;
221 /* Search first megabyte for a valid FTL header */
223 (offset
+ sizeof(header
)) < max_offset
;
224 offset
+= part
->mtd
->erasesize
? : 0x2000) {
226 ret
= part
->mtd
->read(part
->mtd
, offset
, sizeof(header
), &ret
,
227 (unsigned char *)&header
);
232 if (strcmp(header
.DataOrgTuple
+3, "FTL100") == 0) break;
235 if (offset
== max_offset
) {
236 printk(KERN_NOTICE
"ftl_cs: FTL header not found.\n");
239 if ((le16_to_cpu(header
.NumEraseUnits
) > 65536) || header
.BlockSize
!= 9 ||
240 (header
.EraseUnitSize
< 10) || (header
.EraseUnitSize
> 31) ||
241 (header
.NumTransferUnits
>= le16_to_cpu(header
.NumEraseUnits
))) {
242 printk(KERN_NOTICE
"ftl_cs: FTL header corrupt!\n");
245 if ((1 << header
.EraseUnitSize
) != part
->mtd
->erasesize
) {
246 printk(KERN_NOTICE
"ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
247 1 << header
.EraseUnitSize
,part
->mtd
->erasesize
);
250 part
->header
= header
;
254 static int build_maps(partition_t
*part
)
256 erase_unit_header_t header
;
257 u_int16_t xvalid
, xtrans
, i
;
259 int hdr_ok
, ret
= -1;
263 /* Set up erase unit maps */
264 part
->DataUnits
= le16_to_cpu(part
->header
.NumEraseUnits
) -
265 part
->header
.NumTransferUnits
;
266 part
->EUNInfo
= kmalloc(part
->DataUnits
* sizeof(struct eun_info_t
),
270 for (i
= 0; i
< part
->DataUnits
; i
++)
271 part
->EUNInfo
[i
].Offset
= 0xffffffff;
273 kmalloc(part
->header
.NumTransferUnits
* sizeof(struct xfer_info_t
),
279 for (i
= 0; i
< le16_to_cpu(part
->header
.NumEraseUnits
); i
++) {
280 offset
= ((i
+ le16_to_cpu(part
->header
.FirstPhysicalEUN
))
281 << part
->header
.EraseUnitSize
);
282 ret
= part
->mtd
->read(part
->mtd
, offset
, sizeof(header
), &retval
,
283 (unsigned char *)&header
);
289 /* Is this a transfer partition? */
290 hdr_ok
= (strcmp(header
.DataOrgTuple
+3, "FTL100") == 0);
291 if (hdr_ok
&& (le16_to_cpu(header
.LogicalEUN
) < part
->DataUnits
) &&
292 (part
->EUNInfo
[le16_to_cpu(header
.LogicalEUN
)].Offset
== 0xffffffff)) {
293 part
->EUNInfo
[le16_to_cpu(header
.LogicalEUN
)].Offset
= offset
;
294 part
->EUNInfo
[le16_to_cpu(header
.LogicalEUN
)].EraseCount
=
295 le32_to_cpu(header
.EraseCount
);
298 if (xtrans
== part
->header
.NumTransferUnits
) {
299 printk(KERN_NOTICE
"ftl_cs: format error: too many "
300 "transfer units!\n");
303 if (hdr_ok
&& (le16_to_cpu(header
.LogicalEUN
) == 0xffff)) {
304 part
->XferInfo
[xtrans
].state
= XFER_PREPARED
;
305 part
->XferInfo
[xtrans
].EraseCount
= le32_to_cpu(header
.EraseCount
);
307 part
->XferInfo
[xtrans
].state
= XFER_UNKNOWN
;
308 /* Pick anything reasonable for the erase count */
309 part
->XferInfo
[xtrans
].EraseCount
=
310 le32_to_cpu(part
->header
.EraseCount
);
312 part
->XferInfo
[xtrans
].Offset
= offset
;
316 /* Check for format trouble */
317 header
= part
->header
;
318 if ((xtrans
!= header
.NumTransferUnits
) ||
319 (xvalid
+xtrans
!= le16_to_cpu(header
.NumEraseUnits
))) {
320 printk(KERN_NOTICE
"ftl_cs: format error: erase units "
325 /* Set up virtual page map */
326 blocks
= le32_to_cpu(header
.FormattedSize
) >> header
.BlockSize
;
327 part
->VirtualBlockMap
= vmalloc(blocks
* sizeof(u_int32_t
));
328 if (!part
->VirtualBlockMap
)
331 memset(part
->VirtualBlockMap
, 0xff, blocks
* sizeof(u_int32_t
));
332 part
->BlocksPerUnit
= (1 << header
.EraseUnitSize
) >> header
.BlockSize
;
334 part
->bam_cache
= kmalloc(part
->BlocksPerUnit
* sizeof(u_int32_t
),
336 if (!part
->bam_cache
)
337 goto out_VirtualBlockMap
;
339 part
->bam_index
= 0xffff;
342 for (i
= 0; i
< part
->DataUnits
; i
++) {
343 part
->EUNInfo
[i
].Free
= 0;
344 part
->EUNInfo
[i
].Deleted
= 0;
345 offset
= part
->EUNInfo
[i
].Offset
+ le32_to_cpu(header
.BAMOffset
);
347 ret
= part
->mtd
->read(part
->mtd
, offset
,
348 part
->BlocksPerUnit
* sizeof(u_int32_t
), &retval
,
349 (unsigned char *)part
->bam_cache
);
354 for (j
= 0; j
< part
->BlocksPerUnit
; j
++) {
355 if (BLOCK_FREE(le32_to_cpu(part
->bam_cache
[j
]))) {
356 part
->EUNInfo
[i
].Free
++;
358 } else if ((BLOCK_TYPE(le32_to_cpu(part
->bam_cache
[j
])) == BLOCK_DATA
) &&
359 (BLOCK_NUMBER(le32_to_cpu(part
->bam_cache
[j
])) < blocks
))
360 part
->VirtualBlockMap
[BLOCK_NUMBER(le32_to_cpu(part
->bam_cache
[j
]))] =
361 (i
<< header
.EraseUnitSize
) + (j
<< header
.BlockSize
);
362 else if (BLOCK_DELETED(le32_to_cpu(part
->bam_cache
[j
])))
363 part
->EUNInfo
[i
].Deleted
++;
371 kfree(part
->bam_cache
);
373 vfree(part
->VirtualBlockMap
);
375 kfree(part
->XferInfo
);
377 kfree(part
->EUNInfo
);
382 /*======================================================================
384 Erase_xfer() schedules an asynchronous erase operation for a
387 ======================================================================*/
389 static int erase_xfer(partition_t
*part
,
393 struct xfer_info_t
*xfer
;
394 struct erase_info
*erase
;
396 xfer
= &part
->XferInfo
[xfernum
];
397 DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer
->Offset
);
398 xfer
->state
= XFER_ERASING
;
400 /* Is there a free erase slot? Always in MTD. */
403 erase
=kmalloc(sizeof(struct erase_info
), GFP_KERNEL
);
407 erase
->callback
= ftl_erase_callback
;
408 erase
->addr
= xfer
->Offset
;
409 erase
->len
= 1 << part
->header
.EraseUnitSize
;
410 erase
->priv
= (u_long
)part
;
412 ret
= part
->mtd
->erase(part
->mtd
, erase
);
422 /*======================================================================
424 Prepare_xfer() takes a freshly erased transfer unit and gives
425 it an appropriate header.
427 ======================================================================*/
429 static void ftl_erase_callback(struct erase_info
*erase
)
432 struct xfer_info_t
*xfer
;
435 /* Look up the transfer unit */
436 part
= (partition_t
*)(erase
->priv
);
438 for (i
= 0; i
< part
->header
.NumTransferUnits
; i
++)
439 if (part
->XferInfo
[i
].Offset
== erase
->addr
) break;
441 if (i
== part
->header
.NumTransferUnits
) {
442 printk(KERN_NOTICE
"ftl_cs: internal error: "
443 "erase lookup failed!\n");
447 xfer
= &part
->XferInfo
[i
];
448 if (erase
->state
== MTD_ERASE_DONE
)
449 xfer
->state
= XFER_ERASED
;
451 xfer
->state
= XFER_FAILED
;
452 printk(KERN_NOTICE
"ftl_cs: erase failed: state = %d\n",
458 } /* ftl_erase_callback */
460 static int prepare_xfer(partition_t
*part
, int i
)
462 erase_unit_header_t header
;
463 struct xfer_info_t
*xfer
;
469 xfer
= &part
->XferInfo
[i
];
470 xfer
->state
= XFER_FAILED
;
472 DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer
->Offset
);
474 /* Write the transfer unit header */
475 header
= part
->header
;
476 header
.LogicalEUN
= cpu_to_le16(0xffff);
477 header
.EraseCount
= cpu_to_le32(xfer
->EraseCount
);
479 ret
= part
->mtd
->write(part
->mtd
, xfer
->Offset
, sizeof(header
),
480 &retlen
, (u_char
*)&header
);
486 /* Write the BAM stub */
487 nbam
= (part
->BlocksPerUnit
* sizeof(u_int32_t
) +
488 le32_to_cpu(part
->header
.BAMOffset
) + SECTOR_SIZE
- 1) / SECTOR_SIZE
;
490 offset
= xfer
->Offset
+ le32_to_cpu(part
->header
.BAMOffset
);
491 ctl
= cpu_to_le32(BLOCK_CONTROL
);
493 for (i
= 0; i
< nbam
; i
++, offset
+= sizeof(u_int32_t
)) {
495 ret
= part
->mtd
->write(part
->mtd
, offset
, sizeof(u_int32_t
),
496 &retlen
, (u_char
*)&ctl
);
501 xfer
->state
= XFER_PREPARED
;
506 /*======================================================================
508 Copy_erase_unit() takes a full erase block and a transfer unit,
509 copies everything to the transfer unit, then swaps the block
512 All data blocks are copied to the corresponding blocks in the
513 target unit, so the virtual block map does not need to be
516 ======================================================================*/
518 static int copy_erase_unit(partition_t
*part
, u_int16_t srcunit
,
521 u_char buf
[SECTOR_SIZE
];
522 struct eun_info_t
*eun
;
523 struct xfer_info_t
*xfer
;
524 u_int32_t src
, dest
, free
, i
;
529 u_int16_t srcunitswap
= cpu_to_le16(srcunit
);
531 eun
= &part
->EUNInfo
[srcunit
];
532 xfer
= &part
->XferInfo
[xferunit
];
533 DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
534 eun
->Offset
, xfer
->Offset
);
537 /* Read current BAM */
538 if (part
->bam_index
!= srcunit
) {
540 offset
= eun
->Offset
+ le32_to_cpu(part
->header
.BAMOffset
);
542 ret
= part
->mtd
->read(part
->mtd
, offset
,
543 part
->BlocksPerUnit
* sizeof(u_int32_t
),
544 &retlen
, (u_char
*) (part
->bam_cache
));
546 /* mark the cache bad, in case we get an error later */
547 part
->bam_index
= 0xffff;
550 printk( KERN_WARNING
"ftl: Failed to read BAM cache in copy_erase_unit()!\n");
555 /* Write the LogicalEUN for the transfer unit */
556 xfer
->state
= XFER_UNKNOWN
;
557 offset
= xfer
->Offset
+ 20; /* Bad! */
558 unit
= cpu_to_le16(0x7fff);
560 ret
= part
->mtd
->write(part
->mtd
, offset
, sizeof(u_int16_t
),
561 &retlen
, (u_char
*) &unit
);
564 printk( KERN_WARNING
"ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
568 /* Copy all data blocks from source unit to transfer unit */
569 src
= eun
->Offset
; dest
= xfer
->Offset
;
573 for (i
= 0; i
< part
->BlocksPerUnit
; i
++) {
574 switch (BLOCK_TYPE(le32_to_cpu(part
->bam_cache
[i
]))) {
576 /* This gets updated later */
579 case BLOCK_REPLACEMENT
:
580 ret
= part
->mtd
->read(part
->mtd
, src
, SECTOR_SIZE
,
581 &retlen
, (u_char
*) buf
);
583 printk(KERN_WARNING
"ftl: Error reading old xfer unit in copy_erase_unit\n");
588 ret
= part
->mtd
->write(part
->mtd
, dest
, SECTOR_SIZE
,
589 &retlen
, (u_char
*) buf
);
591 printk(KERN_WARNING
"ftl: Error writing new xfer unit in copy_erase_unit\n");
597 /* All other blocks must be free */
598 part
->bam_cache
[i
] = cpu_to_le32(0xffffffff);
606 /* Write the BAM to the transfer unit */
607 ret
= part
->mtd
->write(part
->mtd
, xfer
->Offset
+ le32_to_cpu(part
->header
.BAMOffset
),
608 part
->BlocksPerUnit
* sizeof(int32_t), &retlen
,
609 (u_char
*)part
->bam_cache
);
611 printk( KERN_WARNING
"ftl: Error writing BAM in copy_erase_unit\n");
616 /* All clear? Then update the LogicalEUN again */
617 ret
= part
->mtd
->write(part
->mtd
, xfer
->Offset
+ 20, sizeof(u_int16_t
),
618 &retlen
, (u_char
*)&srcunitswap
);
621 printk(KERN_WARNING
"ftl: Error writing new LogicalEUN in copy_erase_unit\n");
626 /* Update the maps and usage stats*/
627 i
= xfer
->EraseCount
;
628 xfer
->EraseCount
= eun
->EraseCount
;
631 xfer
->Offset
= eun
->Offset
;
633 part
->FreeTotal
-= eun
->Free
;
634 part
->FreeTotal
+= free
;
638 /* Now, the cache should be valid for the new block */
639 part
->bam_index
= srcunit
;
642 } /* copy_erase_unit */
644 /*======================================================================
646 reclaim_block() picks a full erase unit and a transfer unit and
647 then calls copy_erase_unit() to copy one to the other. Then, it
648 schedules an erase on the expired block.
650 What's a good way to decide which transfer unit and which erase
651 unit to use? Beats me. My way is to always pick the transfer
652 unit with the fewest erases, and usually pick the data unit with
653 the most deleted blocks. But with a small probability, pick the
654 oldest data unit instead. This means that we generally postpone
655 the next reclaimation as long as possible, but shuffle static
656 stuff around a bit for wear leveling.
658 ======================================================================*/
660 static int reclaim_block(partition_t
*part
)
662 u_int16_t i
, eun
, xfer
;
666 DEBUG(0, "ftl_cs: reclaiming space...\n");
667 DEBUG(3, "NumTransferUnits == %x\n", part
->header
.NumTransferUnits
);
668 /* Pick the least erased transfer unit */
669 best
= 0xffffffff; xfer
= 0xffff;
672 for (i
= 0; i
< part
->header
.NumTransferUnits
; i
++) {
674 if (part
->XferInfo
[i
].state
== XFER_UNKNOWN
) {
675 DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i
);
679 if (part
->XferInfo
[i
].state
== XFER_ERASING
) {
680 DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i
);
684 else if (part
->XferInfo
[i
].state
== XFER_ERASED
) {
685 DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i
);
687 prepare_xfer(part
, i
);
689 if (part
->XferInfo
[i
].state
== XFER_PREPARED
) {
690 DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i
);
692 if (part
->XferInfo
[i
].EraseCount
<= best
) {
693 best
= part
->XferInfo
[i
].EraseCount
;
698 DEBUG(3,"XferInfo[%d].state == %x\n",i
, part
->XferInfo
[i
].state
);
701 if (xfer
== 0xffff) {
703 DEBUG(1, "ftl_cs: waiting for transfer "
704 "unit to be prepared...\n");
706 part
->mtd
->sync(part
->mtd
);
710 printk(KERN_NOTICE
"ftl_cs: reclaim failed: no "
711 "suitable transfer units!\n");
713 DEBUG(1, "ftl_cs: reclaim failed: no "
714 "suitable transfer units!\n");
719 } while (xfer
== 0xffff);
722 if ((jiffies
% shuffle_freq
) == 0) {
723 DEBUG(1, "ftl_cs: recycling freshest block...\n");
725 for (i
= 0; i
< part
->DataUnits
; i
++)
726 if (part
->EUNInfo
[i
].EraseCount
<= best
) {
727 best
= part
->EUNInfo
[i
].EraseCount
;
732 for (i
= 0; i
< part
->DataUnits
; i
++)
733 if (part
->EUNInfo
[i
].Deleted
>= best
) {
734 best
= part
->EUNInfo
[i
].Deleted
;
740 printk(KERN_NOTICE
"ftl_cs: reclaim failed: "
741 "no free blocks!\n");
743 DEBUG(1,"ftl_cs: reclaim failed: "
744 "no free blocks!\n");
749 ret
= copy_erase_unit(part
, eun
, xfer
);
751 erase_xfer(part
, xfer
);
753 printk(KERN_NOTICE
"ftl_cs: copy_erase_unit failed!\n");
755 } /* reclaim_block */
757 /*======================================================================
759 Find_free() searches for a free block. If necessary, it updates
760 the BAM cache for the erase unit containing the free block. It
761 returns the block index -- the erase unit is just the currently
762 cached unit. If there are no free blocks, it returns 0 -- this
763 is never a valid data block because it contains the header.
765 ======================================================================*/
768 static void dump_lists(partition_t
*part
)
771 printk(KERN_DEBUG
"ftl_cs: Free total = %d\n", part
->FreeTotal
);
772 for (i
= 0; i
< part
->DataUnits
; i
++)
773 printk(KERN_DEBUG
"ftl_cs: unit %d: %d phys, %d free, "
775 part
->EUNInfo
[i
].Offset
>> part
->header
.EraseUnitSize
,
776 part
->EUNInfo
[i
].Free
, part
->EUNInfo
[i
].Deleted
);
780 static u_int32_t
find_free(partition_t
*part
)
787 /* Find an erase unit with some free space */
788 stop
= (part
->bam_index
== 0xffff) ? 0 : part
->bam_index
;
791 if (part
->EUNInfo
[eun
].Free
!= 0) break;
792 /* Wrap around at end of table */
793 if (++eun
== part
->DataUnits
) eun
= 0;
794 } while (eun
!= stop
);
796 if (part
->EUNInfo
[eun
].Free
== 0)
799 /* Is this unit's BAM cached? */
800 if (eun
!= part
->bam_index
) {
801 /* Invalidate cache */
802 part
->bam_index
= 0xffff;
804 ret
= part
->mtd
->read(part
->mtd
,
805 part
->EUNInfo
[eun
].Offset
+ le32_to_cpu(part
->header
.BAMOffset
),
806 part
->BlocksPerUnit
* sizeof(u_int32_t
),
807 &retlen
, (u_char
*) (part
->bam_cache
));
810 printk(KERN_WARNING
"ftl: Error reading BAM in find_free\n");
813 part
->bam_index
= eun
;
816 /* Find a free block */
817 for (blk
= 0; blk
< part
->BlocksPerUnit
; blk
++)
818 if (BLOCK_FREE(le32_to_cpu(part
->bam_cache
[blk
]))) break;
819 if (blk
== part
->BlocksPerUnit
) {
825 printk(KERN_NOTICE
"ftl_cs: bad free list!\n");
828 DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk
, eun
);
833 /*======================================================================
835 This gets a memory handle for the region corresponding to the
838 ======================================================================*/
840 static int ftl_open(struct inode
*inode
, struct file
*file
)
842 int minor
= minor(inode
->i_rdev
);
843 partition_t
*partition
;
845 if (minor
>>4 >= MAX_MTD_DEVICES
)
848 partition
= myparts
[minor
>>4];
853 if (partition
->state
!= FTL_FORMATTED
)
856 if (ftl_gendisk
.part
[minor
].nr_sects
== 0)
859 if (!get_mtd_device(partition
->mtd
, -1))
860 return /* -E'SBUGGEREDOFF */ -ENXIO
;
862 if ((file
->f_mode
& 2) && !(partition
->mtd
->flags
& MTD_CLEAR_BITS
) ) {
863 put_mtd_device(partition
->mtd
);
867 DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor
);
869 atomic_inc(&partition
->open
);
874 /*====================================================================*/
876 static release_t
ftl_close(struct inode
*inode
, struct file
*file
)
878 int minor
= minor(inode
->i_rdev
);
879 partition_t
*part
= myparts
[minor
>> 4];
882 DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor
);
884 /* Flush all writes */
885 invalidate_device(inode
->i_rdev
, 1);
887 /* Wait for any pending erase operations to complete */
889 part
->mtd
->sync(part
->mtd
);
891 for (i
= 0; i
< part
->header
.NumTransferUnits
; i
++) {
892 if (part
->XferInfo
[i
].state
== XFER_ERASED
)
893 prepare_xfer(part
, i
);
896 atomic_dec(&part
->open
);
898 put_mtd_device(part
->mtd
);
903 /*======================================================================
905 Read a series of sectors from an FTL partition.
907 ======================================================================*/
909 static int ftl_read(partition_t
*part
, caddr_t buffer
,
910 u_long sector
, u_long nblocks
)
912 u_int32_t log_addr
, bsize
;
915 size_t offset
, retlen
;
917 DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
918 part
, sector
, nblocks
);
919 if (!(part
->state
& FTL_FORMATTED
)) {
920 printk(KERN_NOTICE
"ftl_cs: bad partition\n");
923 bsize
= 1 << part
->header
.EraseUnitSize
;
925 for (i
= 0; i
< nblocks
; i
++) {
926 if (((sector
+i
) * SECTOR_SIZE
) >= le32_to_cpu(part
->header
.FormattedSize
)) {
927 printk(KERN_NOTICE
"ftl_cs: bad read offset\n");
930 log_addr
= part
->VirtualBlockMap
[sector
+i
];
931 if (log_addr
== 0xffffffff)
932 memset(buffer
, 0, SECTOR_SIZE
);
934 offset
= (part
->EUNInfo
[log_addr
/ bsize
].Offset
935 + (log_addr
% bsize
));
936 ret
= part
->mtd
->read(part
->mtd
, offset
, SECTOR_SIZE
,
937 &retlen
, (u_char
*) buffer
);
940 printk(KERN_WARNING
"Error reading MTD device in ftl_read()\n");
944 buffer
+= SECTOR_SIZE
;
949 /*======================================================================
951 Write a series of sectors to an FTL partition
953 ======================================================================*/
955 static int set_bam_entry(partition_t
*part
, u_int32_t log_addr
,
958 u_int32_t bsize
, blk
, le_virt_addr
;
964 size_t retlen
, offset
;
966 DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
967 part
, log_addr
, virt_addr
);
968 bsize
= 1 << part
->header
.EraseUnitSize
;
969 eun
= log_addr
/ bsize
;
970 blk
= (log_addr
% bsize
) / SECTOR_SIZE
;
971 offset
= (part
->EUNInfo
[eun
].Offset
+ blk
* sizeof(u_int32_t
) +
972 le32_to_cpu(part
->header
.BAMOffset
));
975 ret
= part
->mtd
->read(part
->mtd
, offset
, sizeof(u_int32_t
),
976 &retlen
, (u_char
*)&old_addr
);
978 printk(KERN_WARNING
"ftl: Error reading old_addr in set_bam_entry: %d\n",ret
);
981 old_addr
= le32_to_cpu(old_addr
);
983 if (((virt_addr
== 0xfffffffe) && !BLOCK_FREE(old_addr
)) ||
984 ((virt_addr
== 0) && (BLOCK_TYPE(old_addr
) != BLOCK_DATA
)) ||
985 (!BLOCK_DELETED(virt_addr
) && (old_addr
!= 0xfffffffe))) {
988 printk(KERN_NOTICE
"ftl_cs: set_bam_entry() inconsistency!\n");
989 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, old = 0x%x"
990 ", new = 0x%x\n", log_addr
, old_addr
, virt_addr
);
995 le_virt_addr
= cpu_to_le32(virt_addr
);
996 if (part
->bam_index
== eun
) {
998 if (le32_to_cpu(part
->bam_cache
[blk
]) != old_addr
) {
1001 printk(KERN_NOTICE
"ftl_cs: set_bam_entry() "
1002 "inconsistency!\n");
1003 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, cache"
1005 le32_to_cpu(part
->bam_cache
[blk
]), old_addr
);
1010 part
->bam_cache
[blk
] = le_virt_addr
;
1012 ret
= part
->mtd
->write(part
->mtd
, offset
, sizeof(u_int32_t
),
1013 &retlen
, (u_char
*)&le_virt_addr
);
1016 printk(KERN_NOTICE
"ftl_cs: set_bam_entry() failed!\n");
1017 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, new = 0x%x\n",
1018 log_addr
, virt_addr
);
1021 } /* set_bam_entry */
1023 static int ftl_write(partition_t
*part
, caddr_t buffer
,
1024 u_long sector
, u_long nblocks
)
1026 u_int32_t bsize
, log_addr
, virt_addr
, old_addr
, blk
;
1029 size_t retlen
, offset
;
1031 DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
1032 part
, sector
, nblocks
);
1033 if (!(part
->state
& FTL_FORMATTED
)) {
1034 printk(KERN_NOTICE
"ftl_cs: bad partition\n");
1037 /* See if we need to reclaim space, before we start */
1038 while (part
->FreeTotal
< nblocks
) {
1039 ret
= reclaim_block(part
);
1044 bsize
= 1 << part
->header
.EraseUnitSize
;
1046 virt_addr
= sector
* SECTOR_SIZE
| BLOCK_DATA
;
1047 for (i
= 0; i
< nblocks
; i
++) {
1048 if (virt_addr
>= le32_to_cpu(part
->header
.FormattedSize
)) {
1049 printk(KERN_NOTICE
"ftl_cs: bad write offset\n");
1053 /* Grab a free block */
1054 blk
= find_free(part
);
1058 printk(KERN_NOTICE
"ftl_cs: internal error: "
1059 "no free blocks!\n");
1063 /* Tag the BAM entry, and write the new block */
1064 log_addr
= part
->bam_index
* bsize
+ blk
* SECTOR_SIZE
;
1065 part
->EUNInfo
[part
->bam_index
].Free
--;
1067 if (set_bam_entry(part
, log_addr
, 0xfffffffe))
1069 part
->EUNInfo
[part
->bam_index
].Deleted
++;
1070 offset
= (part
->EUNInfo
[part
->bam_index
].Offset
+
1072 ret
= part
->mtd
->write(part
->mtd
, offset
, SECTOR_SIZE
, &retlen
,
1076 printk(KERN_NOTICE
"ftl_cs: block write failed!\n");
1077 printk(KERN_NOTICE
"ftl_cs: log_addr = 0x%x, virt_addr"
1078 " = 0x%x, Offset = 0x%x\n", log_addr
, virt_addr
,
1083 /* Only delete the old entry when the new entry is ready */
1084 old_addr
= part
->VirtualBlockMap
[sector
+i
];
1085 if (old_addr
!= 0xffffffff) {
1086 part
->VirtualBlockMap
[sector
+i
] = 0xffffffff;
1087 part
->EUNInfo
[old_addr
/bsize
].Deleted
++;
1088 if (set_bam_entry(part
, old_addr
, 0))
1092 /* Finally, set up the new pointers */
1093 if (set_bam_entry(part
, log_addr
, virt_addr
))
1095 part
->VirtualBlockMap
[sector
+i
] = log_addr
;
1096 part
->EUNInfo
[part
->bam_index
].Deleted
--;
1098 buffer
+= SECTOR_SIZE
;
1099 virt_addr
+= SECTOR_SIZE
;
1104 /*======================================================================
1106 IOCTL calls for getting device parameters.
1108 ======================================================================*/
1110 static int ftl_ioctl(struct inode
*inode
, struct file
*file
,
1111 u_int cmd
, u_long arg
)
1113 struct hd_geometry
*geo
= (struct hd_geometry
*)arg
;
1114 int ret
= 0, minor
= minor(inode
->i_rdev
);
1115 partition_t
*part
= myparts
[minor
>> 4];
1119 return -ENODEV
; /* How? */
1123 ret
= verify_area(VERIFY_WRITE
, (long *)arg
, sizeof(*geo
));
1124 if (ret
) return ret
;
1125 /* Sort of arbitrary: round size down to 4K boundary */
1126 sect
= le32_to_cpu(part
->header
.FormattedSize
)/SECTOR_SIZE
;
1127 put_user(1, (char *)&geo
->heads
);
1128 put_user(8, (char *)&geo
->sectors
);
1129 put_user((sect
>>3), (short *)&geo
->cylinders
);
1130 put_user(get_start_sect(inode
->i_rdev
), (u_long
*)&geo
->start
);
1133 ret
= put_user(ftl_hd
[minor
].nr_sects
, (unsigned long *)arg
);
1136 ret
= put_user((u64
)ftl_hd
[minor
].nr_sects
<< 9, (u64
*)arg
);
1139 ret
= ftl_reread_partitions(inode
->i_rdev
);
1144 ret
= blk_ioctl(inode
->i_bdev
, cmd
, arg
);
1153 /*======================================================================
1155 Handler for block device requests
1157 ======================================================================*/
1159 static int ftl_reread_partitions(kdev_t dev
)
1161 int minor
= minor(dev
);
1162 partition_t
*part
= myparts
[minor
>> 4];
1165 DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor
);
1166 if ((atomic_read(&part
->open
) > 1)) {
1170 res
= wipe_partitions(dev
);
1176 register_disk(&ftl_gendisk
, whole
>> PART_BITS
, MAX_PART
,
1177 &ftl_blk_fops
, le32_to_cpu(part
->header
.FormattedSize
)/SECTOR_SIZE
);
1182 /*======================================================================
1184 Handler for block device requests
1186 ======================================================================*/
1188 static void do_ftl_request(request_arg_t
)
1197 minor
= minor(CURRENT
->rq_dev
);
1199 part
= myparts
[minor
>> 4];
1203 switch (CURRENT
->cmd
) {
1205 ret
= ftl_read(part
, CURRENT
->buffer
,
1206 CURRENT
->sector
+ftl_hd
[minor
].start_sect
,
1207 CURRENT
->current_nr_sectors
);
1208 if (ret
) printk("ftl_read returned %d\n", ret
);
1212 ret
= ftl_write(part
, CURRENT
->buffer
,
1213 CURRENT
->sector
+ftl_hd
[minor
].start_sect
,
1214 CURRENT
->current_nr_sectors
);
1215 if (ret
) printk("ftl_write returned %d\n", ret
);
1219 panic("ftl_cs: unknown block command!\n");
1224 printk("NULL part in ftl_request\n");
1228 CURRENT
->sector
+= CURRENT
->current_nr_sectors
;
1231 end_request((ret
== 0) ? 1 : 0);
1233 } /* do_ftl_request */
1235 /*====================================================================*/
1237 void ftl_freepart(partition_t
*part
)
1239 if (part
->VirtualBlockMap
) {
1240 vfree(part
->VirtualBlockMap
);
1241 part
->VirtualBlockMap
= NULL
;
1243 if (part
->VirtualPageMap
) {
1244 kfree(part
->VirtualPageMap
);
1245 part
->VirtualPageMap
= NULL
;
1247 if (part
->EUNInfo
) {
1248 kfree(part
->EUNInfo
);
1249 part
->EUNInfo
= NULL
;
1251 if (part
->XferInfo
) {
1252 kfree(part
->XferInfo
);
1253 part
->XferInfo
= NULL
;
1255 if (part
->bam_cache
) {
1256 kfree(part
->bam_cache
);
1257 part
->bam_cache
= NULL
;
1260 } /* ftl_freepart */
1262 static void ftl_notify_add(struct mtd_info
*mtd
)
1264 partition_t
*partition
;
1267 for (device
=0; device
< MAX_MTD_DEVICES
&& myparts
[device
]; device
++)
1270 if (device
== MAX_MTD_DEVICES
) {
1271 printk(KERN_NOTICE
"Maximum number of FTL partitions reached\n"
1272 "Not scanning <%s>\n", mtd
->name
);
1276 partition
= kmalloc(sizeof(partition_t
), GFP_KERNEL
);
1279 printk(KERN_WARNING
"No memory to scan for FTL on %s\n",
1284 memset(partition
, 0, sizeof(partition_t
));
1286 partition
->mtd
= mtd
;
1288 if ((scan_header(partition
) == 0) &&
1289 (build_maps(partition
) == 0)) {
1291 partition
->state
= FTL_FORMATTED
;
1292 atomic_set(&partition
->open
, 0);
1293 myparts
[device
] = partition
;
1294 ftl_reread_partitions(device
<< 4);
1296 printk(KERN_INFO
"ftl_cs: opening %d kb FTL partition\n",
1297 le32_to_cpu(partition
->header
.FormattedSize
) >> 10);
1303 static void ftl_notify_remove(struct mtd_info
*mtd
)
1307 /* Q: What happens if you try to remove a device which has
1308 * a currently-open FTL partition on it?
1310 * A: You don't. The ftl_open routine is responsible for
1311 * increasing the use count of the driver module which
1315 /* That's the theory, anyway :) */
1317 for (i
=0; i
< MAX_MTD_DEVICES
; i
++)
1318 if (myparts
[i
] && myparts
[i
]->mtd
== mtd
) {
1320 if (myparts
[i
]->state
== FTL_FORMATTED
)
1321 ftl_freepart(myparts
[i
]);
1323 myparts
[i
]->state
= 0;
1324 for (j
=0; j
<16; j
++) {
1325 ftl_gendisk
.part
[j
].nr_sects
=0;
1326 ftl_gendisk
.part
[j
].start_sect
=0;
1337 memset(myparts
, 0, sizeof(myparts
));
1339 DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n");
1341 if (register_blkdev(FTL_MAJOR
, "ftl", &ftl_blk_fops
)) {
1342 printk(KERN_NOTICE
"ftl_cs: unable to grab major "
1343 "device number!\n");
1347 for (i
= 0; i
< MAX_DEV
*MAX_PART
; i
++) {
1348 ftl_hd
[i
].nr_sects
= 0;
1349 ftl_hd
[i
].start_sect
= 0;
1351 ftl_gendisk
.major
= FTL_MAJOR
;
1352 blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR
), &do_ftl_request
);
1353 add_gendisk(&ftl_gendisk
);
1355 register_mtd_user(&ftl_notifier
);
1360 static void __exit
cleanup_ftl(void)
1362 unregister_mtd_user(&ftl_notifier
);
1364 unregister_blkdev(FTL_MAJOR
, "ftl");
1365 blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR
));
1366 blk_clear(FTL_MAJOR
);
1368 del_gendisk(&ftl_gendisk
);
1371 module_init(init_ftl
);
1372 module_exit(cleanup_ftl
);
1375 MODULE_LICENSE("Dual MPL/GPL");
1376 MODULE_AUTHOR("David Hinds <dhinds@sonic.net>");
1377 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");