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