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