Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / mtd / ftl.c
1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2  *
3  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
4  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
5  *
6  * Based on:
7  */
8 /*======================================================================
9
10     A Flash Translation Layer memory card driver
11
12     This driver implements a disk-like block device driver with an
13     apparent block size of 512 bytes for flash memory cards.
14
15     ftl_cs.c 1.62 2000/02/01 00:59:04
16
17     The contents of this file are subject to the Mozilla Public
18     License Version 1.1 (the "License"); you may not use this file
19     except in compliance with the License. You may obtain a copy of
20     the License at http://www.mozilla.org/MPL/
21
22     Software distributed under the License is distributed on an "AS
23     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
24     implied. See the License for the specific language governing
25     rights and limitations under the License.
26
27     The initial developer of the original code is David A. Hinds
28     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
29     are Copyright © 1999 David A. Hinds.  All Rights Reserved.
30
31     Alternatively, the contents of this file may be used under the
32     terms of the GNU General Public License version 2 (the "GPL"), in
33     which case the provisions of the GPL are applicable instead of the
34     above.  If you wish to allow the use of your version of this file
35     only under the terms of the GPL and not to allow others to use
36     your version of this file under the MPL, indicate your decision
37     by deleting the provisions above and replace them with the notice
38     and other provisions required by the GPL.  If you do not delete
39     the provisions above, a recipient may use your version of this
40     file under either the MPL or the GPL.
41
42     LEGAL NOTE: The FTL format is patented by M-Systems.  They have
43     granted a license for its use with PCMCIA devices:
44
45      "M-Systems grants a royalty-free, non-exclusive license under
46       any presently existing M-Systems intellectual property rights
47       necessary for the design and development of FTL-compatible
48       drivers, file systems and utilities using the data formats with
49       PCMCIA PC Cards as described in the PCMCIA Flash Translation
50       Layer (FTL) Specification."
51
52     Use of the FTL format for non-PCMCIA applications may be an
53     infringement of these patents.  For additional information,
54     contact M-Systems directly. M-Systems since acquired by Sandisk. 
55
56 ======================================================================*/
57 #include <linux/mtd/blktrans.h>
58 #include <linux/module.h>
59 #include <linux/mtd/mtd.h>
60 /*#define PSYCHO_DEBUG */
61
62 #include <linux/kernel.h>
63 #include <linux/ptrace.h>
64 #include <linux/slab.h>
65 #include <linux/string.h>
66 #include <linux/timer.h>
67 #include <linux/major.h>
68 #include <linux/fs.h>
69 #include <linux/init.h>
70 #include <linux/hdreg.h>
71 #include <linux/vmalloc.h>
72 #include <linux/blkpg.h>
73 #include <asm/uaccess.h>
74
75 #include <linux/mtd/ftl.h>
76
77 /*====================================================================*/
78
79 /* Parameters that can be set with 'insmod' */
80 static int shuffle_freq = 50;
81 module_param(shuffle_freq, int, 0);
82
83 /*====================================================================*/
84
85 /* Major device # for FTL device */
86 #ifndef FTL_MAJOR
87 #define FTL_MAJOR       44
88 #endif
89
90
91 /*====================================================================*/
92
93 /* Maximum number of separate memory devices we'll allow */
94 #define MAX_DEV         4
95
96 /* Maximum number of regions per device */
97 #define MAX_REGION      4
98
99 /* Maximum number of partitions in an FTL region */
100 #define PART_BITS       4
101
102 /* Maximum number of outstanding erase requests per socket */
103 #define MAX_ERASE       8
104
105 /* Sector size -- shouldn't need to change */
106 #define SECTOR_SIZE     512
107
108
109 /* Each memory region corresponds to a minor device */
110 typedef struct partition_t {
111     struct mtd_blktrans_dev mbd;
112     uint32_t            state;
113     uint32_t            *VirtualBlockMap;
114     uint32_t            FreeTotal;
115     struct eun_info_t {
116         uint32_t                Offset;
117         uint32_t                EraseCount;
118         uint32_t                Free;
119         uint32_t                Deleted;
120     } *EUNInfo;
121     struct xfer_info_t {
122         uint32_t                Offset;
123         uint32_t                EraseCount;
124         uint16_t                state;
125     } *XferInfo;
126     uint16_t            bam_index;
127     uint32_t            *bam_cache;
128     uint16_t            DataUnits;
129     uint32_t            BlocksPerUnit;
130     erase_unit_header_t header;
131 } partition_t;
132
133 /* Partition state flags */
134 #define FTL_FORMATTED   0x01
135
136 /* Transfer unit states */
137 #define XFER_UNKNOWN    0x00
138 #define XFER_ERASING    0x01
139 #define XFER_ERASED     0x02
140 #define XFER_PREPARED   0x03
141 #define XFER_FAILED     0x04
142
143 /*====================================================================*/
144
145
146 static void ftl_erase_callback(struct erase_info *done);
147
148
149 /*======================================================================
150
151     Scan_header() checks to see if a memory region contains an FTL
152     partition.  build_maps() reads all the erase unit headers, builds
153     the erase unit map, and then builds the virtual page map.
154
155 ======================================================================*/
156
157 static int scan_header(partition_t *part)
158 {
159     erase_unit_header_t header;
160     loff_t offset, max_offset;
161     size_t ret;
162     int err;
163     part->header.FormattedSize = 0;
164     max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
165     /* Search first megabyte for a valid FTL header */
166     for (offset = 0;
167          (offset + sizeof(header)) < max_offset;
168          offset += part->mbd.mtd->erasesize ? : 0x2000) {
169
170         err = mtd_read(part->mbd.mtd, offset, sizeof(header), &ret,
171                        (unsigned char *)&header);
172
173         if (err)
174             return err;
175
176         if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
177     }
178
179     if (offset == max_offset) {
180         printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
181         return -ENOENT;
182     }
183     if (header.BlockSize != 9 ||
184         (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
185         (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
186         printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
187         return -1;
188     }
189     if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
190         printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
191                1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
192         return -1;
193     }
194     part->header = header;
195     return 0;
196 }
197
198 static int build_maps(partition_t *part)
199 {
200     erase_unit_header_t header;
201     uint16_t xvalid, xtrans, i;
202     unsigned blocks, j;
203     int hdr_ok, ret = -1;
204     ssize_t retval;
205     loff_t offset;
206
207     /* Set up erase unit maps */
208     part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
209         part->header.NumTransferUnits;
210     part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
211                             GFP_KERNEL);
212     if (!part->EUNInfo)
213             goto out;
214     for (i = 0; i < part->DataUnits; i++)
215         part->EUNInfo[i].Offset = 0xffffffff;
216     part->XferInfo =
217         kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
218                 GFP_KERNEL);
219     if (!part->XferInfo)
220             goto out_EUNInfo;
221
222     xvalid = xtrans = 0;
223     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
224         offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
225                       << part->header.EraseUnitSize);
226         ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval,
227                        (unsigned char *)&header);
228
229         if (ret)
230             goto out_XferInfo;
231
232         ret = -1;
233         /* Is this a transfer partition? */
234         hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
235         if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
236             (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
237             part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
238             part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
239                 le32_to_cpu(header.EraseCount);
240             xvalid++;
241         } else {
242             if (xtrans == part->header.NumTransferUnits) {
243                 printk(KERN_NOTICE "ftl_cs: format error: too many "
244                        "transfer units!\n");
245                 goto out_XferInfo;
246             }
247             if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
248                 part->XferInfo[xtrans].state = XFER_PREPARED;
249                 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
250             } else {
251                 part->XferInfo[xtrans].state = XFER_UNKNOWN;
252                 /* Pick anything reasonable for the erase count */
253                 part->XferInfo[xtrans].EraseCount =
254                     le32_to_cpu(part->header.EraseCount);
255             }
256             part->XferInfo[xtrans].Offset = offset;
257             xtrans++;
258         }
259     }
260     /* Check for format trouble */
261     header = part->header;
262     if ((xtrans != header.NumTransferUnits) ||
263         (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
264         printk(KERN_NOTICE "ftl_cs: format error: erase units "
265                "don't add up!\n");
266         goto out_XferInfo;
267     }
268
269     /* Set up virtual page map */
270     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
271     part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t));
272     if (!part->VirtualBlockMap)
273             goto out_XferInfo;
274
275     memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
276     part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
277
278     part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t),
279                               GFP_KERNEL);
280     if (!part->bam_cache)
281             goto out_VirtualBlockMap;
282
283     part->bam_index = 0xffff;
284     part->FreeTotal = 0;
285
286     for (i = 0; i < part->DataUnits; i++) {
287         part->EUNInfo[i].Free = 0;
288         part->EUNInfo[i].Deleted = 0;
289         offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
290
291         ret = mtd_read(part->mbd.mtd, offset,
292                        part->BlocksPerUnit * sizeof(uint32_t), &retval,
293                        (unsigned char *)part->bam_cache);
294
295         if (ret)
296                 goto out_bam_cache;
297
298         for (j = 0; j < part->BlocksPerUnit; j++) {
299             if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
300                 part->EUNInfo[i].Free++;
301                 part->FreeTotal++;
302             } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
303                      (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
304                 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
305                     (i << header.EraseUnitSize) + (j << header.BlockSize);
306             else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
307                 part->EUNInfo[i].Deleted++;
308         }
309     }
310
311     ret = 0;
312     goto out;
313
314 out_bam_cache:
315     kfree(part->bam_cache);
316 out_VirtualBlockMap:
317     vfree(part->VirtualBlockMap);
318 out_XferInfo:
319     kfree(part->XferInfo);
320 out_EUNInfo:
321     kfree(part->EUNInfo);
322 out:
323     return ret;
324 } /* build_maps */
325
326 /*======================================================================
327
328     Erase_xfer() schedules an asynchronous erase operation for a
329     transfer unit.
330
331 ======================================================================*/
332
333 static int erase_xfer(partition_t *part,
334                       uint16_t xfernum)
335 {
336     int ret;
337     struct xfer_info_t *xfer;
338     struct erase_info *erase;
339
340     xfer = &part->XferInfo[xfernum];
341     pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
342     xfer->state = XFER_ERASING;
343
344     /* Is there a free erase slot? Always in MTD. */
345
346
347     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
348     if (!erase)
349             return -ENOMEM;
350
351     erase->mtd = part->mbd.mtd;
352     erase->callback = ftl_erase_callback;
353     erase->addr = xfer->Offset;
354     erase->len = 1 << part->header.EraseUnitSize;
355     erase->priv = (u_long)part;
356
357     ret = mtd_erase(part->mbd.mtd, erase);
358
359     if (!ret)
360             xfer->EraseCount++;
361     else
362             kfree(erase);
363
364     return ret;
365 } /* erase_xfer */
366
367 /*======================================================================
368
369     Prepare_xfer() takes a freshly erased transfer unit and gives
370     it an appropriate header.
371
372 ======================================================================*/
373
374 static void ftl_erase_callback(struct erase_info *erase)
375 {
376     partition_t *part;
377     struct xfer_info_t *xfer;
378     int i;
379
380     /* Look up the transfer unit */
381     part = (partition_t *)(erase->priv);
382
383     for (i = 0; i < part->header.NumTransferUnits; i++)
384         if (part->XferInfo[i].Offset == erase->addr) break;
385
386     if (i == part->header.NumTransferUnits) {
387         printk(KERN_NOTICE "ftl_cs: internal error: "
388                "erase lookup failed!\n");
389         return;
390     }
391
392     xfer = &part->XferInfo[i];
393     if (erase->state == MTD_ERASE_DONE)
394         xfer->state = XFER_ERASED;
395     else {
396         xfer->state = XFER_FAILED;
397         printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
398                erase->state);
399     }
400
401     kfree(erase);
402
403 } /* ftl_erase_callback */
404
405 static int prepare_xfer(partition_t *part, int i)
406 {
407     erase_unit_header_t header;
408     struct xfer_info_t *xfer;
409     int nbam, ret;
410     uint32_t ctl;
411     ssize_t retlen;
412     loff_t offset;
413
414     xfer = &part->XferInfo[i];
415     xfer->state = XFER_FAILED;
416
417     pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
418
419     /* Write the transfer unit header */
420     header = part->header;
421     header.LogicalEUN = cpu_to_le16(0xffff);
422     header.EraseCount = cpu_to_le32(xfer->EraseCount);
423
424     ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen,
425                     (u_char *)&header);
426
427     if (ret) {
428         return ret;
429     }
430
431     /* Write the BAM stub */
432     nbam = (part->BlocksPerUnit * sizeof(uint32_t) +
433             le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
434
435     offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
436     ctl = cpu_to_le32(BLOCK_CONTROL);
437
438     for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
439
440         ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
441                         (u_char *)&ctl);
442
443         if (ret)
444             return ret;
445     }
446     xfer->state = XFER_PREPARED;
447     return 0;
448
449 } /* prepare_xfer */
450
451 /*======================================================================
452
453     Copy_erase_unit() takes a full erase block and a transfer unit,
454     copies everything to the transfer unit, then swaps the block
455     pointers.
456
457     All data blocks are copied to the corresponding blocks in the
458     target unit, so the virtual block map does not need to be
459     updated.
460
461 ======================================================================*/
462
463 static int copy_erase_unit(partition_t *part, uint16_t srcunit,
464                            uint16_t xferunit)
465 {
466     u_char buf[SECTOR_SIZE];
467     struct eun_info_t *eun;
468     struct xfer_info_t *xfer;
469     uint32_t src, dest, free, i;
470     uint16_t unit;
471     int ret;
472     ssize_t retlen;
473     loff_t offset;
474     uint16_t srcunitswap = cpu_to_le16(srcunit);
475
476     eun = &part->EUNInfo[srcunit];
477     xfer = &part->XferInfo[xferunit];
478     pr_debug("ftl_cs: copying block 0x%x to 0x%x\n",
479           eun->Offset, xfer->Offset);
480
481
482     /* Read current BAM */
483     if (part->bam_index != srcunit) {
484
485         offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
486
487         ret = mtd_read(part->mbd.mtd, offset,
488                        part->BlocksPerUnit * sizeof(uint32_t), &retlen,
489                        (u_char *)(part->bam_cache));
490
491         /* mark the cache bad, in case we get an error later */
492         part->bam_index = 0xffff;
493
494         if (ret) {
495             printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
496             return ret;
497         }
498     }
499
500     /* Write the LogicalEUN for the transfer unit */
501     xfer->state = XFER_UNKNOWN;
502     offset = xfer->Offset + 20; /* Bad! */
503     unit = cpu_to_le16(0x7fff);
504
505     ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen,
506                     (u_char *)&unit);
507
508     if (ret) {
509         printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
510         return ret;
511     }
512
513     /* Copy all data blocks from source unit to transfer unit */
514     src = eun->Offset; dest = xfer->Offset;
515
516     free = 0;
517     ret = 0;
518     for (i = 0; i < part->BlocksPerUnit; i++) {
519         switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
520         case BLOCK_CONTROL:
521             /* This gets updated later */
522             break;
523         case BLOCK_DATA:
524         case BLOCK_REPLACEMENT:
525             ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen,
526                            (u_char *)buf);
527             if (ret) {
528                 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
529                 return ret;
530             }
531
532
533             ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen,
534                             (u_char *)buf);
535             if (ret)  {
536                 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
537                 return ret;
538             }
539
540             break;
541         default:
542             /* All other blocks must be free */
543             part->bam_cache[i] = cpu_to_le32(0xffffffff);
544             free++;
545             break;
546         }
547         src += SECTOR_SIZE;
548         dest += SECTOR_SIZE;
549     }
550
551     /* Write the BAM to the transfer unit */
552     ret = mtd_write(part->mbd.mtd,
553                     xfer->Offset + le32_to_cpu(part->header.BAMOffset),
554                     part->BlocksPerUnit * sizeof(int32_t),
555                     &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 = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_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 reclamation 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     uint16_t i, eun, xfer;
610     uint32_t best;
611     int queued, ret;
612
613     pr_debug("ftl_cs: reclaiming space...\n");
614     pr_debug("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                 pr_debug("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                 pr_debug("XferInfo[%d].state == XFER_ERASING\n",i);
628                 n=1;
629                 queued = 1;
630             }
631             else if (part->XferInfo[i].state == XFER_ERASED) {
632                 pr_debug("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                 pr_debug("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                     pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
646
647         }
648         if (xfer == 0xffff) {
649             if (queued) {
650                 pr_debug("ftl_cs: waiting for transfer "
651                       "unit to be prepared...\n");
652                 mtd_sync(part->mbd.mtd);
653             } else {
654                 static int ne = 0;
655                 if (++ne < 5)
656                     printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
657                            "suitable transfer units!\n");
658                 else
659                     pr_debug("ftl_cs: reclaim failed: no "
660                           "suitable transfer units!\n");
661
662                 return -EIO;
663             }
664         }
665     } while (xfer == 0xffff);
666
667     eun = 0;
668     if ((jiffies % shuffle_freq) == 0) {
669         pr_debug("ftl_cs: recycling freshest block...\n");
670         best = 0xffffffff;
671         for (i = 0; i < part->DataUnits; i++)
672             if (part->EUNInfo[i].EraseCount <= best) {
673                 best = part->EUNInfo[i].EraseCount;
674                 eun = i;
675             }
676     } else {
677         best = 0;
678         for (i = 0; i < part->DataUnits; i++)
679             if (part->EUNInfo[i].Deleted >= best) {
680                 best = part->EUNInfo[i].Deleted;
681                 eun = i;
682             }
683         if (best == 0) {
684             static int ne = 0;
685             if (++ne < 5)
686                 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
687                        "no free blocks!\n");
688             else
689                 pr_debug("ftl_cs: reclaim failed: "
690                        "no free blocks!\n");
691
692             return -EIO;
693         }
694     }
695     ret = copy_erase_unit(part, eun, xfer);
696     if (!ret)
697         erase_xfer(part, xfer);
698     else
699         printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
700     return ret;
701 } /* reclaim_block */
702
703 /*======================================================================
704
705     Find_free() searches for a free block.  If necessary, it updates
706     the BAM cache for the erase unit containing the free block.  It
707     returns the block index -- the erase unit is just the currently
708     cached unit.  If there are no free blocks, it returns 0 -- this
709     is never a valid data block because it contains the header.
710
711 ======================================================================*/
712
713 #ifdef PSYCHO_DEBUG
714 static void dump_lists(partition_t *part)
715 {
716     int i;
717     printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
718     for (i = 0; i < part->DataUnits; i++)
719         printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
720                "%d deleted\n", i,
721                part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
722                part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
723 }
724 #endif
725
726 static uint32_t find_free(partition_t *part)
727 {
728     uint16_t stop, eun;
729     uint32_t blk;
730     size_t retlen;
731     int ret;
732
733     /* Find an erase unit with some free space */
734     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
735     eun = stop;
736     do {
737         if (part->EUNInfo[eun].Free != 0) break;
738         /* Wrap around at end of table */
739         if (++eun == part->DataUnits) eun = 0;
740     } while (eun != stop);
741
742     if (part->EUNInfo[eun].Free == 0)
743         return 0;
744
745     /* Is this unit's BAM cached? */
746     if (eun != part->bam_index) {
747         /* Invalidate cache */
748         part->bam_index = 0xffff;
749
750         ret = mtd_read(part->mbd.mtd,
751                        part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
752                        part->BlocksPerUnit * sizeof(uint32_t),
753                        &retlen,
754                        (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     pr_debug("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     uint32_t log_addr, bsize;
791     u_long i;
792     int ret;
793     size_t offset, retlen;
794
795     pr_debug("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 = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
815                            (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, uint32_t log_addr,
834                          uint32_t virt_addr)
835 {
836     uint32_t bsize, blk, le_virt_addr;
837 #ifdef PSYCHO_DEBUG
838     uint32_t old_addr;
839 #endif
840     uint16_t eun;
841     int ret;
842     size_t retlen, offset;
843
844     pr_debug("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(uint32_t) +
850                   le32_to_cpu(part->header.BAMOffset));
851
852 #ifdef PSYCHO_DEBUG
853     ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
854                    (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 = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
891                     (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     uint32_t bsize, log_addr, virt_addr, old_addr, blk;
905     u_long i;
906     int ret;
907     size_t retlen, offset;
908
909     pr_debug("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 = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer);
951
952         if (ret) {
953             printk(KERN_NOTICE "ftl_cs: block write failed!\n");
954             printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
955                    " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
956                    offset);
957             return -EIO;
958         }
959
960         /* Only delete the old entry when the new entry is ready */
961         old_addr = part->VirtualBlockMap[sector+i];
962         if (old_addr != 0xffffffff) {
963             part->VirtualBlockMap[sector+i] = 0xffffffff;
964             part->EUNInfo[old_addr/bsize].Deleted++;
965             if (set_bam_entry(part, old_addr, 0))
966                 return -EIO;
967         }
968
969         /* Finally, set up the new pointers */
970         if (set_bam_entry(part, log_addr, virt_addr))
971             return -EIO;
972         part->VirtualBlockMap[sector+i] = log_addr;
973         part->EUNInfo[part->bam_index].Deleted--;
974
975         buffer += SECTOR_SIZE;
976         virt_addr += SECTOR_SIZE;
977     }
978     return 0;
979 } /* ftl_write */
980
981 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
982 {
983         partition_t *part = (void *)dev;
984         u_long sect;
985
986         /* Sort of arbitrary: round size down to 4KiB boundary */
987         sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
988
989         geo->heads = 1;
990         geo->sectors = 8;
991         geo->cylinders = sect >> 3;
992
993         return 0;
994 }
995
996 static int ftl_readsect(struct mtd_blktrans_dev *dev,
997                               unsigned long block, char *buf)
998 {
999         return ftl_read((void *)dev, buf, block, 1);
1000 }
1001
1002 static int ftl_writesect(struct mtd_blktrans_dev *dev,
1003                               unsigned long block, char *buf)
1004 {
1005         return ftl_write((void *)dev, buf, block, 1);
1006 }
1007
1008 static int ftl_discardsect(struct mtd_blktrans_dev *dev,
1009                            unsigned long sector, unsigned nr_sects)
1010 {
1011         partition_t *part = (void *)dev;
1012         uint32_t bsize = 1 << part->header.EraseUnitSize;
1013
1014         pr_debug("FTL erase sector %ld for %d sectors\n",
1015               sector, nr_sects);
1016
1017         while (nr_sects) {
1018                 uint32_t old_addr = part->VirtualBlockMap[sector];
1019                 if (old_addr != 0xffffffff) {
1020                         part->VirtualBlockMap[sector] = 0xffffffff;
1021                         part->EUNInfo[old_addr/bsize].Deleted++;
1022                         if (set_bam_entry(part, old_addr, 0))
1023                                 return -EIO;
1024                 }
1025                 nr_sects--;
1026                 sector++;
1027         }
1028
1029         return 0;
1030 }
1031 /*====================================================================*/
1032
1033 static void ftl_freepart(partition_t *part)
1034 {
1035         vfree(part->VirtualBlockMap);
1036         part->VirtualBlockMap = NULL;
1037         kfree(part->EUNInfo);
1038         part->EUNInfo = NULL;
1039         kfree(part->XferInfo);
1040         part->XferInfo = NULL;
1041         kfree(part->bam_cache);
1042         part->bam_cache = NULL;
1043 } /* ftl_freepart */
1044
1045 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1046 {
1047         partition_t *partition;
1048
1049         partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1050
1051         if (!partition) {
1052                 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1053                        mtd->name);
1054                 return;
1055         }
1056
1057         partition->mbd.mtd = mtd;
1058
1059         if ((scan_header(partition) == 0) &&
1060             (build_maps(partition) == 0)) {
1061
1062                 partition->state = FTL_FORMATTED;
1063 #ifdef PCMCIA_DEBUG
1064                 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1065                        le32_to_cpu(partition->header.FormattedSize) >> 10);
1066 #endif
1067                 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1068
1069                 partition->mbd.tr = tr;
1070                 partition->mbd.devnum = -1;
1071                 if (!add_mtd_blktrans_dev((void *)partition))
1072                         return;
1073         }
1074
1075         kfree(partition);
1076 }
1077
1078 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1079 {
1080         del_mtd_blktrans_dev(dev);
1081         ftl_freepart((partition_t *)dev);
1082 }
1083
1084 static struct mtd_blktrans_ops ftl_tr = {
1085         .name           = "ftl",
1086         .major          = FTL_MAJOR,
1087         .part_bits      = PART_BITS,
1088         .blksize        = SECTOR_SIZE,
1089         .readsect       = ftl_readsect,
1090         .writesect      = ftl_writesect,
1091         .discard        = ftl_discardsect,
1092         .getgeo         = ftl_getgeo,
1093         .add_mtd        = ftl_add_mtd,
1094         .remove_dev     = ftl_remove_dev,
1095         .owner          = THIS_MODULE,
1096 };
1097
1098 static int __init init_ftl(void)
1099 {
1100         return register_mtd_blktrans(&ftl_tr);
1101 }
1102
1103 static void __exit cleanup_ftl(void)
1104 {
1105         deregister_mtd_blktrans(&ftl_tr);
1106 }
1107
1108 module_init(init_ftl);
1109 module_exit(cleanup_ftl);
1110
1111
1112 MODULE_LICENSE("Dual MPL/GPL");
1113 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1114 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");