]> err.no Git - linux-2.6/blob - drivers/mtd/ftl.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfashe...
[linux-2.6] / drivers / mtd / ftl.c
1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2  * $Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $
3  *
4  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
5  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
6  *
7  * Based on:
8  */
9 /*======================================================================
10
11     A Flash Translation Layer memory card driver
12
13     This driver implements a disk-like block device driver with an
14     apparent block size of 512 bytes for flash memory cards.
15
16     ftl_cs.c 1.62 2000/02/01 00:59:04
17
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/
22
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.
27
28     The initial developer of the original code is David A. Hinds
29     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
30     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
31
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.
42
43     LEGAL NOTE: The FTL format is patented by M-Systems.  They have
44     granted a license for its use with PCMCIA devices:
45
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."
52
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.
56
57 ======================================================================*/
58 #include <linux/mtd/blktrans.h>
59 #include <linux/module.h>
60 #include <linux/mtd/mtd.h>
61 /*#define PSYCHO_DEBUG */
62
63 #include <linux/kernel.h>
64 #include <linux/ptrace.h>
65 #include <linux/slab.h>
66 #include <linux/string.h>
67 #include <linux/timer.h>
68 #include <linux/major.h>
69 #include <linux/fs.h>
70 #include <linux/init.h>
71 #include <linux/hdreg.h>
72 #include <linux/vmalloc.h>
73 #include <linux/blkpg.h>
74 #include <asm/uaccess.h>
75
76 #include <linux/mtd/ftl.h>
77
78 /*====================================================================*/
79
80 /* Parameters that can be set with 'insmod' */
81 static int shuffle_freq = 50;
82 module_param(shuffle_freq, int, 0);
83
84 /*====================================================================*/
85
86 /* Major device # for FTL device */
87 #ifndef FTL_MAJOR
88 #define FTL_MAJOR       44
89 #endif
90
91
92 /*====================================================================*/
93
94 /* Maximum number of separate memory devices we'll allow */
95 #define MAX_DEV         4
96
97 /* Maximum number of regions per device */
98 #define MAX_REGION      4
99
100 /* Maximum number of partitions in an FTL region */
101 #define PART_BITS       4
102
103 /* Maximum number of outstanding erase requests per socket */
104 #define MAX_ERASE       8
105
106 /* Sector size -- shouldn't need to change */
107 #define SECTOR_SIZE     512
108
109
110 /* Each memory region corresponds to a minor device */
111 typedef struct partition_t {
112     struct mtd_blktrans_dev mbd;
113     u_int32_t           state;
114     u_int32_t           *VirtualBlockMap;
115     u_int32_t           *VirtualPageMap;
116     u_int32_t           FreeTotal;
117     struct eun_info_t {
118         u_int32_t               Offset;
119         u_int32_t               EraseCount;
120         u_int32_t               Free;
121         u_int32_t               Deleted;
122     } *EUNInfo;
123     struct xfer_info_t {
124         u_int32_t               Offset;
125         u_int32_t               EraseCount;
126         u_int16_t               state;
127     } *XferInfo;
128     u_int16_t           bam_index;
129     u_int32_t           *bam_cache;
130     u_int16_t           DataUnits;
131     u_int32_t           BlocksPerUnit;
132     erase_unit_header_t header;
133 } partition_t;
134
135 /* Partition state flags */
136 #define FTL_FORMATTED   0x01
137
138 /* Transfer unit states */
139 #define XFER_UNKNOWN    0x00
140 #define XFER_ERASING    0x01
141 #define XFER_ERASED     0x02
142 #define XFER_PREPARED   0x03
143 #define XFER_FAILED     0x04
144
145 /*====================================================================*/
146
147
148 static void ftl_erase_callback(struct erase_info *done);
149
150
151 /*======================================================================
152
153     Scan_header() checks to see if a memory region contains an FTL
154     partition.  build_maps() reads all the erase unit headers, builds
155     the erase unit map, and then builds the virtual page map.
156
157 ======================================================================*/
158
159 static int scan_header(partition_t *part)
160 {
161     erase_unit_header_t header;
162     loff_t offset, max_offset;
163     size_t ret;
164     int err;
165     part->header.FormattedSize = 0;
166     max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
167     /* Search first megabyte for a valid FTL header */
168     for (offset = 0;
169          (offset + sizeof(header)) < max_offset;
170          offset += part->mbd.mtd->erasesize ? : 0x2000) {
171
172         err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
173                               (unsigned char *)&header);
174
175         if (err)
176             return err;
177
178         if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
179     }
180
181     if (offset == max_offset) {
182         printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
183         return -ENOENT;
184     }
185     if (header.BlockSize != 9 ||
186         (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
187         (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
188         printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
189         return -1;
190     }
191     if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
192         printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
193                1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
194         return -1;
195     }
196     part->header = header;
197     return 0;
198 }
199
200 static int build_maps(partition_t *part)
201 {
202     erase_unit_header_t header;
203     u_int16_t xvalid, xtrans, i;
204     u_int blocks, j;
205     int hdr_ok, ret = -1;
206     ssize_t retval;
207     loff_t offset;
208
209     /* Set up erase unit maps */
210     part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
211         part->header.NumTransferUnits;
212     part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
213                             GFP_KERNEL);
214     if (!part->EUNInfo)
215             goto out;
216     for (i = 0; i < part->DataUnits; i++)
217         part->EUNInfo[i].Offset = 0xffffffff;
218     part->XferInfo =
219         kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
220                 GFP_KERNEL);
221     if (!part->XferInfo)
222             goto out_EUNInfo;
223
224     xvalid = xtrans = 0;
225     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
226         offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
227                       << part->header.EraseUnitSize);
228         ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
229                               (unsigned char *)&header);
230
231         if (ret)
232             goto out_XferInfo;
233
234         ret = -1;
235         /* Is this a transfer partition? */
236         hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
237         if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
238             (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
239             part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
240             part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
241                 le32_to_cpu(header.EraseCount);
242             xvalid++;
243         } else {
244             if (xtrans == part->header.NumTransferUnits) {
245                 printk(KERN_NOTICE "ftl_cs: format error: too many "
246                        "transfer units!\n");
247                 goto out_XferInfo;
248             }
249             if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
250                 part->XferInfo[xtrans].state = XFER_PREPARED;
251                 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
252             } else {
253                 part->XferInfo[xtrans].state = XFER_UNKNOWN;
254                 /* Pick anything reasonable for the erase count */
255                 part->XferInfo[xtrans].EraseCount =
256                     le32_to_cpu(part->header.EraseCount);
257             }
258             part->XferInfo[xtrans].Offset = offset;
259             xtrans++;
260         }
261     }
262     /* Check for format trouble */
263     header = part->header;
264     if ((xtrans != header.NumTransferUnits) ||
265         (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
266         printk(KERN_NOTICE "ftl_cs: format error: erase units "
267                "don't add up!\n");
268         goto out_XferInfo;
269     }
270
271     /* Set up virtual page map */
272     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
273     part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
274     if (!part->VirtualBlockMap)
275             goto out_XferInfo;
276
277     memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
278     part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
279
280     part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
281                               GFP_KERNEL);
282     if (!part->bam_cache)
283             goto out_VirtualBlockMap;
284
285     part->bam_index = 0xffff;
286     part->FreeTotal = 0;
287
288     for (i = 0; i < part->DataUnits; i++) {
289         part->EUNInfo[i].Free = 0;
290         part->EUNInfo[i].Deleted = 0;
291         offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
292
293         ret = part->mbd.mtd->read(part->mbd.mtd, offset,
294                               part->BlocksPerUnit * sizeof(u_int32_t), &retval,
295                               (unsigned char *)part->bam_cache);
296
297         if (ret)
298                 goto out_bam_cache;
299
300         for (j = 0; j < part->BlocksPerUnit; j++) {
301             if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
302                 part->EUNInfo[i].Free++;
303                 part->FreeTotal++;
304             } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
305                      (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
306                 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
307                     (i << header.EraseUnitSize) + (j << header.BlockSize);
308             else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
309                 part->EUNInfo[i].Deleted++;
310         }
311     }
312
313     ret = 0;
314     goto out;
315
316 out_bam_cache:
317     kfree(part->bam_cache);
318 out_VirtualBlockMap:
319     vfree(part->VirtualBlockMap);
320 out_XferInfo:
321     kfree(part->XferInfo);
322 out_EUNInfo:
323     kfree(part->EUNInfo);
324 out:
325     return ret;
326 } /* build_maps */
327
328 /*======================================================================
329
330     Erase_xfer() schedules an asynchronous erase operation for a
331     transfer unit.
332
333 ======================================================================*/
334
335 static int erase_xfer(partition_t *part,
336                       u_int16_t xfernum)
337 {
338     int ret;
339     struct xfer_info_t *xfer;
340     struct erase_info *erase;
341
342     xfer = &part->XferInfo[xfernum];
343     DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
344     xfer->state = XFER_ERASING;
345
346     /* Is there a free erase slot? Always in MTD. */
347
348
349     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
350     if (!erase)
351             return -ENOMEM;
352
353     erase->mtd = part->mbd.mtd;
354     erase->callback = ftl_erase_callback;
355     erase->addr = xfer->Offset;
356     erase->len = 1 << part->header.EraseUnitSize;
357     erase->priv = (u_long)part;
358
359     ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
360
361     if (!ret)
362             xfer->EraseCount++;
363     else
364             kfree(erase);
365
366     return ret;
367 } /* erase_xfer */
368
369 /*======================================================================
370
371     Prepare_xfer() takes a freshly erased transfer unit and gives
372     it an appropriate header.
373
374 ======================================================================*/
375
376 static void ftl_erase_callback(struct erase_info *erase)
377 {
378     partition_t *part;
379     struct xfer_info_t *xfer;
380     int i;
381
382     /* Look up the transfer unit */
383     part = (partition_t *)(erase->priv);
384
385     for (i = 0; i < part->header.NumTransferUnits; i++)
386         if (part->XferInfo[i].Offset == erase->addr) break;
387
388     if (i == part->header.NumTransferUnits) {
389         printk(KERN_NOTICE "ftl_cs: internal error: "
390                "erase lookup failed!\n");
391         return;
392     }
393
394     xfer = &part->XferInfo[i];
395     if (erase->state == MTD_ERASE_DONE)
396         xfer->state = XFER_ERASED;
397     else {
398         xfer->state = XFER_FAILED;
399         printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
400                erase->state);
401     }
402
403     kfree(erase);
404
405 } /* ftl_erase_callback */
406
407 static int prepare_xfer(partition_t *part, int i)
408 {
409     erase_unit_header_t header;
410     struct xfer_info_t *xfer;
411     int nbam, ret;
412     u_int32_t ctl;
413     ssize_t retlen;
414     loff_t offset;
415
416     xfer = &part->XferInfo[i];
417     xfer->state = XFER_FAILED;
418
419     DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
420
421     /* Write the transfer unit header */
422     header = part->header;
423     header.LogicalEUN = cpu_to_le16(0xffff);
424     header.EraseCount = cpu_to_le32(xfer->EraseCount);
425
426     ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
427                            &retlen, (u_char *)&header);
428
429     if (ret) {
430         return ret;
431     }
432
433     /* Write the BAM stub */
434     nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
435             le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
436
437     offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
438     ctl = cpu_to_le32(BLOCK_CONTROL);
439
440     for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
441
442         ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
443                                &retlen, (u_char *)&ctl);
444
445         if (ret)
446             return ret;
447     }
448     xfer->state = XFER_PREPARED;
449     return 0;
450
451 } /* prepare_xfer */
452
453 /*======================================================================
454
455     Copy_erase_unit() takes a full erase block and a transfer unit,
456     copies everything to the transfer unit, then swaps the block
457     pointers.
458
459     All data blocks are copied to the corresponding blocks in the
460     target unit, so the virtual block map does not need to be
461     updated.
462
463 ======================================================================*/
464
465 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
466                            u_int16_t xferunit)
467 {
468     u_char buf[SECTOR_SIZE];
469     struct eun_info_t *eun;
470     struct xfer_info_t *xfer;
471     u_int32_t src, dest, free, i;
472     u_int16_t unit;
473     int ret;
474     ssize_t retlen;
475     loff_t offset;
476     u_int16_t srcunitswap = cpu_to_le16(srcunit);
477
478     eun = &part->EUNInfo[srcunit];
479     xfer = &part->XferInfo[xferunit];
480     DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
481           eun->Offset, xfer->Offset);
482
483
484     /* Read current BAM */
485     if (part->bam_index != srcunit) {
486
487         offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
488
489         ret = part->mbd.mtd->read(part->mbd.mtd, offset,
490                               part->BlocksPerUnit * sizeof(u_int32_t),
491                               &retlen, (u_char *) (part->bam_cache));
492
493         /* mark the cache bad, in case we get an error later */
494         part->bam_index = 0xffff;
495
496         if (ret) {
497             printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
498             return ret;
499         }
500     }
501
502     /* Write the LogicalEUN for the transfer unit */
503     xfer->state = XFER_UNKNOWN;
504     offset = xfer->Offset + 20; /* Bad! */
505     unit = cpu_to_le16(0x7fff);
506
507     ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
508                            &retlen, (u_char *) &unit);
509
510     if (ret) {
511         printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
512         return ret;
513     }
514
515     /* Copy all data blocks from source unit to transfer unit */
516     src = eun->Offset; dest = xfer->Offset;
517
518     free = 0;
519     ret = 0;
520     for (i = 0; i < part->BlocksPerUnit; i++) {
521         switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
522         case BLOCK_CONTROL:
523             /* This gets updated later */
524             break;
525         case BLOCK_DATA:
526         case BLOCK_REPLACEMENT:
527             ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
528                         &retlen, (u_char *) buf);
529             if (ret) {
530                 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
531                 return ret;
532             }
533
534
535             ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
536                         &retlen, (u_char *) buf);
537             if (ret)  {
538                 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
539                 return ret;
540             }
541
542             break;
543         default:
544             /* All other blocks must be free */
545             part->bam_cache[i] = cpu_to_le32(0xffffffff);
546             free++;
547             break;
548         }
549         src += SECTOR_SIZE;
550         dest += SECTOR_SIZE;
551     }
552
553     /* Write the BAM to the transfer unit */
554     ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
555                     part->BlocksPerUnit * sizeof(int32_t), &retlen,
556                     (u_char *)part->bam_cache);
557     if (ret) {
558         printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
559         return ret;
560     }
561
562
563     /* All clear? Then update the LogicalEUN again */
564     ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
565                            &retlen, (u_char *)&srcunitswap);
566
567     if (ret) {
568         printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
569         return ret;
570     }
571
572
573     /* Update the maps and usage stats*/
574     i = xfer->EraseCount;
575     xfer->EraseCount = eun->EraseCount;
576     eun->EraseCount = i;
577     i = xfer->Offset;
578     xfer->Offset = eun->Offset;
579     eun->Offset = i;
580     part->FreeTotal -= eun->Free;
581     part->FreeTotal += free;
582     eun->Free = free;
583     eun->Deleted = 0;
584
585     /* Now, the cache should be valid for the new block */
586     part->bam_index = srcunit;
587
588     return 0;
589 } /* copy_erase_unit */
590
591 /*======================================================================
592
593     reclaim_block() picks a full erase unit and a transfer unit and
594     then calls copy_erase_unit() to copy one to the other.  Then, it
595     schedules an erase on the expired block.
596
597     What's a good way to decide which transfer unit and which erase
598     unit to use?  Beats me.  My way is to always pick the transfer
599     unit with the fewest erases, and usually pick the data unit with
600     the most deleted blocks.  But with a small probability, pick the
601     oldest data unit instead.  This means that we generally postpone
602     the next reclaimation as long as possible, but shuffle static
603     stuff around a bit for wear leveling.
604
605 ======================================================================*/
606
607 static int reclaim_block(partition_t *part)
608 {
609     u_int16_t i, eun, xfer;
610     u_int32_t best;
611     int queued, ret;
612
613     DEBUG(0, "ftl_cs: reclaiming space...\n");
614     DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
615     /* Pick the least erased transfer unit */
616     best = 0xffffffff; xfer = 0xffff;
617     do {
618         queued = 0;
619         for (i = 0; i < part->header.NumTransferUnits; i++) {
620             int n=0;
621             if (part->XferInfo[i].state == XFER_UNKNOWN) {
622                 DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
623                 n=1;
624                 erase_xfer(part, i);
625             }
626             if (part->XferInfo[i].state == XFER_ERASING) {
627                 DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
628                 n=1;
629                 queued = 1;
630             }
631             else if (part->XferInfo[i].state == XFER_ERASED) {
632                 DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
633                 n=1;
634                 prepare_xfer(part, i);
635             }
636             if (part->XferInfo[i].state == XFER_PREPARED) {
637                 DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
638                 n=1;
639                 if (part->XferInfo[i].EraseCount <= best) {
640                     best = part->XferInfo[i].EraseCount;
641                     xfer = i;
642                 }
643             }
644                 if (!n)
645                     DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
646
647         }
648         if (xfer == 0xffff) {
649             if (queued) {
650                 DEBUG(1, "ftl_cs: waiting for transfer "
651                       "unit to be prepared...\n");
652                 if (part->mbd.mtd->sync)
653                         part->mbd.mtd->sync(part->mbd.mtd);
654             } else {
655                 static int ne = 0;
656                 if (++ne < 5)
657                     printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
658                            "suitable transfer units!\n");
659                 else
660                     DEBUG(1, "ftl_cs: reclaim failed: no "
661                           "suitable transfer units!\n");
662
663                 return -EIO;
664             }
665         }
666     } while (xfer == 0xffff);
667
668     eun = 0;
669     if ((jiffies % shuffle_freq) == 0) {
670         DEBUG(1, "ftl_cs: recycling freshest block...\n");
671         best = 0xffffffff;
672         for (i = 0; i < part->DataUnits; i++)
673             if (part->EUNInfo[i].EraseCount <= best) {
674                 best = part->EUNInfo[i].EraseCount;
675                 eun = i;
676             }
677     } else {
678         best = 0;
679         for (i = 0; i < part->DataUnits; i++)
680             if (part->EUNInfo[i].Deleted >= best) {
681                 best = part->EUNInfo[i].Deleted;
682                 eun = i;
683             }
684         if (best == 0) {
685             static int ne = 0;
686             if (++ne < 5)
687                 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
688                        "no free blocks!\n");
689             else
690                 DEBUG(1,"ftl_cs: reclaim failed: "
691                        "no free blocks!\n");
692
693             return -EIO;
694         }
695     }
696     ret = copy_erase_unit(part, eun, xfer);
697     if (!ret)
698         erase_xfer(part, xfer);
699     else
700         printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
701     return ret;
702 } /* reclaim_block */
703
704 /*======================================================================
705
706     Find_free() searches for a free block.  If necessary, it updates
707     the BAM cache for the erase unit containing the free block.  It
708     returns the block index -- the erase unit is just the currently
709     cached unit.  If there are no free blocks, it returns 0 -- this
710     is never a valid data block because it contains the header.
711
712 ======================================================================*/
713
714 #ifdef PSYCHO_DEBUG
715 static void dump_lists(partition_t *part)
716 {
717     int i;
718     printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
719     for (i = 0; i < part->DataUnits; i++)
720         printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
721                "%d deleted\n", i,
722                part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
723                part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
724 }
725 #endif
726
727 static u_int32_t find_free(partition_t *part)
728 {
729     u_int16_t stop, eun;
730     u_int32_t blk;
731     size_t retlen;
732     int ret;
733
734     /* Find an erase unit with some free space */
735     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
736     eun = stop;
737     do {
738         if (part->EUNInfo[eun].Free != 0) break;
739         /* Wrap around at end of table */
740         if (++eun == part->DataUnits) eun = 0;
741     } while (eun != stop);
742
743     if (part->EUNInfo[eun].Free == 0)
744         return 0;
745
746     /* Is this unit's BAM cached? */
747     if (eun != part->bam_index) {
748         /* Invalidate cache */
749         part->bam_index = 0xffff;
750
751         ret = part->mbd.mtd->read(part->mbd.mtd,
752                        part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
753                        part->BlocksPerUnit * sizeof(u_int32_t),
754                        &retlen, (u_char *) (part->bam_cache));
755
756         if (ret) {
757             printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
758             return 0;
759         }
760         part->bam_index = eun;
761     }
762
763     /* Find a free block */
764     for (blk = 0; blk < part->BlocksPerUnit; blk++)
765         if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
766     if (blk == part->BlocksPerUnit) {
767 #ifdef PSYCHO_DEBUG
768         static int ne = 0;
769         if (++ne == 1)
770             dump_lists(part);
771 #endif
772         printk(KERN_NOTICE "ftl_cs: bad free list!\n");
773         return 0;
774     }
775     DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
776     return blk;
777
778 } /* find_free */
779
780
781 /*======================================================================
782
783     Read a series of sectors from an FTL partition.
784
785 ======================================================================*/
786
787 static int ftl_read(partition_t *part, caddr_t buffer,
788                     u_long sector, u_long nblocks)
789 {
790     u_int32_t log_addr, bsize;
791     u_long i;
792     int ret;
793     size_t offset, retlen;
794
795     DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
796           part, sector, nblocks);
797     if (!(part->state & FTL_FORMATTED)) {
798         printk(KERN_NOTICE "ftl_cs: bad partition\n");
799         return -EIO;
800     }
801     bsize = 1 << part->header.EraseUnitSize;
802
803     for (i = 0; i < nblocks; i++) {
804         if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
805             printk(KERN_NOTICE "ftl_cs: bad read offset\n");
806             return -EIO;
807         }
808         log_addr = part->VirtualBlockMap[sector+i];
809         if (log_addr == 0xffffffff)
810             memset(buffer, 0, SECTOR_SIZE);
811         else {
812             offset = (part->EUNInfo[log_addr / bsize].Offset
813                           + (log_addr % bsize));
814             ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
815                            &retlen, (u_char *) buffer);
816
817             if (ret) {
818                 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
819                 return ret;
820             }
821         }
822         buffer += SECTOR_SIZE;
823     }
824     return 0;
825 } /* ftl_read */
826
827 /*======================================================================
828
829     Write a series of sectors to an FTL partition
830
831 ======================================================================*/
832
833 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
834                          u_int32_t virt_addr)
835 {
836     u_int32_t bsize, blk, le_virt_addr;
837 #ifdef PSYCHO_DEBUG
838     u_int32_t old_addr;
839 #endif
840     u_int16_t eun;
841     int ret;
842     size_t retlen, offset;
843
844     DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
845           part, log_addr, virt_addr);
846     bsize = 1 << part->header.EraseUnitSize;
847     eun = log_addr / bsize;
848     blk = (log_addr % bsize) / SECTOR_SIZE;
849     offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
850                   le32_to_cpu(part->header.BAMOffset));
851
852 #ifdef PSYCHO_DEBUG
853     ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
854                         &retlen, (u_char *)&old_addr);
855     if (ret) {
856         printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
857         return ret;
858     }
859     old_addr = le32_to_cpu(old_addr);
860
861     if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
862         ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
863         (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
864         static int ne = 0;
865         if (++ne < 5) {
866             printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
867             printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"
868                    ", new = 0x%x\n", log_addr, old_addr, virt_addr);
869         }
870         return -EIO;
871     }
872 #endif
873     le_virt_addr = cpu_to_le32(virt_addr);
874     if (part->bam_index == eun) {
875 #ifdef PSYCHO_DEBUG
876         if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
877             static int ne = 0;
878             if (++ne < 5) {
879                 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
880                        "inconsistency!\n");
881                 printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"
882                        " = 0x%x\n",
883                        le32_to_cpu(part->bam_cache[blk]), old_addr);
884             }
885             return -EIO;
886         }
887 #endif
888         part->bam_cache[blk] = le_virt_addr;
889     }
890     ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
891                             &retlen, (u_char *)&le_virt_addr);
892
893     if (ret) {
894         printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
895         printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",
896                log_addr, virt_addr);
897     }
898     return ret;
899 } /* set_bam_entry */
900
901 static int ftl_write(partition_t *part, caddr_t buffer,
902                      u_long sector, u_long nblocks)
903 {
904     u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
905     u_long i;
906     int ret;
907     size_t retlen, offset;
908
909     DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
910           part, sector, nblocks);
911     if (!(part->state & FTL_FORMATTED)) {
912         printk(KERN_NOTICE "ftl_cs: bad partition\n");
913         return -EIO;
914     }
915     /* See if we need to reclaim space, before we start */
916     while (part->FreeTotal < nblocks) {
917         ret = reclaim_block(part);
918         if (ret)
919             return ret;
920     }
921
922     bsize = 1 << part->header.EraseUnitSize;
923
924     virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
925     for (i = 0; i < nblocks; i++) {
926         if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
927             printk(KERN_NOTICE "ftl_cs: bad write offset\n");
928             return -EIO;
929         }
930
931         /* Grab a free block */
932         blk = find_free(part);
933         if (blk == 0) {
934             static int ne = 0;
935             if (++ne < 5)
936                 printk(KERN_NOTICE "ftl_cs: internal error: "
937                        "no free blocks!\n");
938             return -ENOSPC;
939         }
940
941         /* Tag the BAM entry, and write the new block */
942         log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
943         part->EUNInfo[part->bam_index].Free--;
944         part->FreeTotal--;
945         if (set_bam_entry(part, log_addr, 0xfffffffe))
946             return -EIO;
947         part->EUNInfo[part->bam_index].Deleted++;
948         offset = (part->EUNInfo[part->bam_index].Offset +
949                       blk * SECTOR_SIZE);
950         ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
951                                      buffer);
952
953         if (ret) {
954             printk(KERN_NOTICE "ftl_cs: block write failed!\n");
955             printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
956                    " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
957                    offset);
958             return -EIO;
959         }
960
961         /* Only delete the old entry when the new entry is ready */
962         old_addr = part->VirtualBlockMap[sector+i];
963         if (old_addr != 0xffffffff) {
964             part->VirtualBlockMap[sector+i] = 0xffffffff;
965             part->EUNInfo[old_addr/bsize].Deleted++;
966             if (set_bam_entry(part, old_addr, 0))
967                 return -EIO;
968         }
969
970         /* Finally, set up the new pointers */
971         if (set_bam_entry(part, log_addr, virt_addr))
972             return -EIO;
973         part->VirtualBlockMap[sector+i] = log_addr;
974         part->EUNInfo[part->bam_index].Deleted--;
975
976         buffer += SECTOR_SIZE;
977         virt_addr += SECTOR_SIZE;
978     }
979     return 0;
980 } /* ftl_write */
981
982 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
983 {
984         partition_t *part = (void *)dev;
985         u_long sect;
986
987         /* Sort of arbitrary: round size down to 4KiB boundary */
988         sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
989
990         geo->heads = 1;
991         geo->sectors = 8;
992         geo->cylinders = sect >> 3;
993
994         return 0;
995 }
996
997 static int ftl_readsect(struct mtd_blktrans_dev *dev,
998                               unsigned long block, char *buf)
999 {
1000         return ftl_read((void *)dev, buf, block, 1);
1001 }
1002
1003 static int ftl_writesect(struct mtd_blktrans_dev *dev,
1004                               unsigned long block, char *buf)
1005 {
1006         return ftl_write((void *)dev, buf, block, 1);
1007 }
1008
1009 /*====================================================================*/
1010
1011 static void ftl_freepart(partition_t *part)
1012 {
1013         vfree(part->VirtualBlockMap);
1014         part->VirtualBlockMap = NULL;
1015         kfree(part->VirtualPageMap);
1016         part->VirtualPageMap = NULL;
1017         kfree(part->EUNInfo);
1018         part->EUNInfo = NULL;
1019         kfree(part->XferInfo);
1020         part->XferInfo = NULL;
1021         kfree(part->bam_cache);
1022         part->bam_cache = NULL;
1023 } /* ftl_freepart */
1024
1025 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1026 {
1027         partition_t *partition;
1028
1029         partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1030
1031         if (!partition) {
1032                 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1033                        mtd->name);
1034                 return;
1035         }
1036
1037         partition->mbd.mtd = mtd;
1038
1039         if ((scan_header(partition) == 0) &&
1040             (build_maps(partition) == 0)) {
1041
1042                 partition->state = FTL_FORMATTED;
1043 #ifdef PCMCIA_DEBUG
1044                 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1045                        le32_to_cpu(partition->header.FormattedSize) >> 10);
1046 #endif
1047                 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1048
1049                 partition->mbd.tr = tr;
1050                 partition->mbd.devnum = -1;
1051                 if (!add_mtd_blktrans_dev((void *)partition))
1052                         return;
1053         }
1054
1055         ftl_freepart(partition);
1056         kfree(partition);
1057 }
1058
1059 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1060 {
1061         del_mtd_blktrans_dev(dev);
1062         ftl_freepart((partition_t *)dev);
1063         kfree(dev);
1064 }
1065
1066 static struct mtd_blktrans_ops ftl_tr = {
1067         .name           = "ftl",
1068         .major          = FTL_MAJOR,
1069         .part_bits      = PART_BITS,
1070         .blksize        = SECTOR_SIZE,
1071         .readsect       = ftl_readsect,
1072         .writesect      = ftl_writesect,
1073         .getgeo         = ftl_getgeo,
1074         .add_mtd        = ftl_add_mtd,
1075         .remove_dev     = ftl_remove_dev,
1076         .owner          = THIS_MODULE,
1077 };
1078
1079 static int init_ftl(void)
1080 {
1081         DEBUG(0, "$Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $\n");
1082
1083         return register_mtd_blktrans(&ftl_tr);
1084 }
1085
1086 static void __exit cleanup_ftl(void)
1087 {
1088         deregister_mtd_blktrans(&ftl_tr);
1089 }
1090
1091 module_init(init_ftl);
1092 module_exit(cleanup_ftl);
1093
1094
1095 MODULE_LICENSE("Dual MPL/GPL");
1096 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1097 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");