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