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