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