[go: nahoru, domu]

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' */
80static int shuffle_freq = 50;
81module_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 */
110typedef 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
146static 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
157static 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
198static 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
314out_bam_cache:
315    kfree(part->bam_cache);
316out_VirtualBlockMap:
317    vfree(part->VirtualBlockMap);
318out_XferInfo:
319    kfree(part->XferInfo);
320out_EUNInfo:
321    kfree(part->EUNInfo);
322out:
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
333static 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
374static 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
405static 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
463static 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
607static 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
714static 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
726static 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
787static 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
833static 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
901static 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
981static 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
996static 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
1002static 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
1008static 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
1033static 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
1045static 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
1078static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1079{
1080	del_mtd_blktrans_dev(dev);
1081	ftl_freepart((partition_t *)dev);
1082}
1083
1084static 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
1098static int __init init_ftl(void)
1099{
1100	return register_mtd_blktrans(&ftl_tr);
1101}
1102
1103static void __exit cleanup_ftl(void)
1104{
1105	deregister_mtd_blktrans(&ftl_tr);
1106}
1107
1108module_init(init_ftl);
1109module_exit(cleanup_ftl);
1110
1111
1112MODULE_LICENSE("Dual MPL/GPL");
1113MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1114MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
1115