Merge with Linux 2.5.74.
[linux-2.6/linux-mips.git] / drivers / mtd / ftl.c
blob67649391125ccfc14dde79cc53a029540183dd0a
1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2 * $Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $
4 * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
5 * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
7 * Based on:
8 */
9 /*======================================================================
11 A Flash Translation Layer memory card driver
13 This driver implements a disk-like block device driver with an
14 apparent block size of 512 bytes for flash memory cards.
16 ftl_cs.c 1.62 2000/02/01 00:59:04
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/
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.
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.
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.
43 LEGAL NOTE: The FTL format is patented by M-Systems. They have
44 granted a license for its use with PCMCIA devices:
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."
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.
57 ======================================================================*/
58 #include <linux/mtd/blktrans.h>
59 #include <linux/module.h>
60 #include <linux/mtd/mtd.h>
61 /*#define PSYCHO_DEBUG */
63 #include <linux/kernel.h>
64 #include <linux/sched.h>
65 #include <linux/ptrace.h>
66 #include <linux/slab.h>
67 #include <linux/string.h>
68 #include <linux/timer.h>
69 #include <linux/major.h>
70 #include <linux/fs.h>
71 #include <linux/init.h>
72 #include <linux/hdreg.h>
73 #include <linux/vmalloc.h>
74 #include <linux/blkpg.h>
75 #include <asm/uaccess.h>
77 #include <linux/mtd/ftl.h>
79 /*====================================================================*/
81 /* Parameters that can be set with 'insmod' */
82 static int shuffle_freq = 50;
83 MODULE_PARM(shuffle_freq, "i");
85 /*====================================================================*/
87 /* Major device # for FTL device */
88 #ifndef FTL_MAJOR
89 #define FTL_MAJOR 44
90 #endif
93 /*====================================================================*/
95 /* Maximum number of separate memory devices we'll allow */
96 #define MAX_DEV 4
98 /* Maximum number of regions per device */
99 #define MAX_REGION 4
101 /* Maximum number of partitions in an FTL region */
102 #define PART_BITS 4
104 /* Maximum number of outstanding erase requests per socket */
105 #define MAX_ERASE 8
107 /* Sector size -- shouldn't need to change */
108 #define SECTOR_SIZE 512
111 /* Each memory region corresponds to a minor device */
112 typedef struct partition_t {
113 struct mtd_blktrans_dev mbd;
114 u_int32_t state;
115 u_int32_t *VirtualBlockMap;
116 u_int32_t *VirtualPageMap;
117 u_int32_t FreeTotal;
118 struct eun_info_t {
119 u_int32_t Offset;
120 u_int32_t EraseCount;
121 u_int32_t Free;
122 u_int32_t Deleted;
123 } *EUNInfo;
124 struct xfer_info_t {
125 u_int32_t Offset;
126 u_int32_t EraseCount;
127 u_int16_t state;
128 } *XferInfo;
129 u_int16_t bam_index;
130 u_int32_t *bam_cache;
131 u_int16_t DataUnits;
132 u_int32_t BlocksPerUnit;
133 erase_unit_header_t header;
134 #if 0
135 region_info_t region;
136 memory_handle_t handle;
137 #endif
138 } partition_t;
140 void ftl_freepart(partition_t *part);
142 /* Partition state flags */
143 #define FTL_FORMATTED 0x01
145 /* Transfer unit states */
146 #define XFER_UNKNOWN 0x00
147 #define XFER_ERASING 0x01
148 #define XFER_ERASED 0x02
149 #define XFER_PREPARED 0x03
150 #define XFER_FAILED 0x04
152 /*====================================================================*/
155 static void ftl_erase_callback(struct erase_info *done);
158 /*======================================================================
160 Scan_header() checks to see if a memory region contains an FTL
161 partition. build_maps() reads all the erase unit headers, builds
162 the erase unit map, and then builds the virtual page map.
164 ======================================================================*/
166 static int scan_header(partition_t *part)
168 erase_unit_header_t header;
169 loff_t offset, max_offset;
170 int ret;
171 part->header.FormattedSize = 0;
172 max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
173 /* Search first megabyte for a valid FTL header */
174 for (offset = 0;
175 (offset + sizeof(header)) < max_offset;
176 offset += part->mbd.mtd->erasesize ? : 0x2000) {
178 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
179 (unsigned char *)&header);
181 if (ret)
182 return ret;
184 if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
187 if (offset == max_offset) {
188 printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
189 return -ENOENT;
191 if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
192 (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
193 (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
194 printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
195 return -1;
197 if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
198 printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
199 1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
200 return -1;
202 part->header = header;
203 return 0;
206 static int build_maps(partition_t *part)
208 erase_unit_header_t header;
209 u_int16_t xvalid, xtrans, i;
210 u_int blocks, j;
211 int hdr_ok, ret = -1;
212 ssize_t retval;
213 loff_t offset;
215 /* Set up erase unit maps */
216 part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
217 part->header.NumTransferUnits;
218 part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
219 GFP_KERNEL);
220 if (!part->EUNInfo)
221 goto out;
222 for (i = 0; i < part->DataUnits; i++)
223 part->EUNInfo[i].Offset = 0xffffffff;
224 part->XferInfo =
225 kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
226 GFP_KERNEL);
227 if (!part->XferInfo)
228 goto out_EUNInfo;
230 xvalid = xtrans = 0;
231 for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
232 offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
233 << part->header.EraseUnitSize);
234 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
235 (unsigned char *)&header);
237 if (ret)
238 goto out_XferInfo;
240 ret = -1;
241 /* Is this a transfer partition? */
242 hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
243 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
244 (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
245 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
246 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
247 le32_to_cpu(header.EraseCount);
248 xvalid++;
249 } else {
250 if (xtrans == part->header.NumTransferUnits) {
251 printk(KERN_NOTICE "ftl_cs: format error: too many "
252 "transfer units!\n");
253 goto out_XferInfo;
255 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
256 part->XferInfo[xtrans].state = XFER_PREPARED;
257 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
258 } else {
259 part->XferInfo[xtrans].state = XFER_UNKNOWN;
260 /* Pick anything reasonable for the erase count */
261 part->XferInfo[xtrans].EraseCount =
262 le32_to_cpu(part->header.EraseCount);
264 part->XferInfo[xtrans].Offset = offset;
265 xtrans++;
268 /* Check for format trouble */
269 header = part->header;
270 if ((xtrans != header.NumTransferUnits) ||
271 (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
272 printk(KERN_NOTICE "ftl_cs: format error: erase units "
273 "don't add up!\n");
274 goto out_XferInfo;
277 /* Set up virtual page map */
278 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
279 part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
280 if (!part->VirtualBlockMap)
281 goto out_XferInfo;
283 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
284 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
286 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
287 GFP_KERNEL);
288 if (!part->bam_cache)
289 goto out_VirtualBlockMap;
291 part->bam_index = 0xffff;
292 part->FreeTotal = 0;
294 for (i = 0; i < part->DataUnits; i++) {
295 part->EUNInfo[i].Free = 0;
296 part->EUNInfo[i].Deleted = 0;
297 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
299 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
300 part->BlocksPerUnit * sizeof(u_int32_t), &retval,
301 (unsigned char *)part->bam_cache);
303 if (ret)
304 goto out_bam_cache;
306 for (j = 0; j < part->BlocksPerUnit; j++) {
307 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
308 part->EUNInfo[i].Free++;
309 part->FreeTotal++;
310 } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
311 (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
312 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
313 (i << header.EraseUnitSize) + (j << header.BlockSize);
314 else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
315 part->EUNInfo[i].Deleted++;
319 ret = 0;
320 goto out;
322 out_bam_cache:
323 kfree(part->bam_cache);
324 out_VirtualBlockMap:
325 vfree(part->VirtualBlockMap);
326 out_XferInfo:
327 kfree(part->XferInfo);
328 out_EUNInfo:
329 kfree(part->EUNInfo);
330 out:
331 return ret;
332 } /* build_maps */
334 /*======================================================================
336 Erase_xfer() schedules an asynchronous erase operation for a
337 transfer unit.
339 ======================================================================*/
341 static int erase_xfer(partition_t *part,
342 u_int16_t xfernum)
344 int ret;
345 struct xfer_info_t *xfer;
346 struct erase_info *erase;
348 xfer = &part->XferInfo[xfernum];
349 DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
350 xfer->state = XFER_ERASING;
352 /* Is there a free erase slot? Always in MTD. */
355 erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
356 if (!erase)
357 return -ENOMEM;
359 erase->callback = ftl_erase_callback;
360 erase->addr = xfer->Offset;
361 erase->len = 1 << part->header.EraseUnitSize;
362 erase->priv = (u_long)part;
364 ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
366 if (!ret)
367 xfer->EraseCount++;
368 else
369 kfree(erase);
371 return ret;
372 } /* erase_xfer */
374 /*======================================================================
376 Prepare_xfer() takes a freshly erased transfer unit and gives
377 it an appropriate header.
379 ======================================================================*/
381 static void ftl_erase_callback(struct erase_info *erase)
383 partition_t *part;
384 struct xfer_info_t *xfer;
385 int i;
387 /* Look up the transfer unit */
388 part = (partition_t *)(erase->priv);
390 for (i = 0; i < part->header.NumTransferUnits; i++)
391 if (part->XferInfo[i].Offset == erase->addr) break;
393 if (i == part->header.NumTransferUnits) {
394 printk(KERN_NOTICE "ftl_cs: internal error: "
395 "erase lookup failed!\n");
396 return;
399 xfer = &part->XferInfo[i];
400 if (erase->state == MTD_ERASE_DONE)
401 xfer->state = XFER_ERASED;
402 else {
403 xfer->state = XFER_FAILED;
404 printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
405 erase->state);
408 kfree(erase);
410 } /* ftl_erase_callback */
412 static int prepare_xfer(partition_t *part, int i)
414 erase_unit_header_t header;
415 struct xfer_info_t *xfer;
416 int nbam, ret;
417 u_int32_t ctl;
418 ssize_t retlen;
419 loff_t offset;
421 xfer = &part->XferInfo[i];
422 xfer->state = XFER_FAILED;
424 DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
426 /* Write the transfer unit header */
427 header = part->header;
428 header.LogicalEUN = cpu_to_le16(0xffff);
429 header.EraseCount = cpu_to_le32(xfer->EraseCount);
431 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
432 &retlen, (u_char *)&header);
434 if (ret) {
435 return ret;
438 /* Write the BAM stub */
439 nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
440 le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
442 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
443 ctl = cpu_to_le32(BLOCK_CONTROL);
445 for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
447 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
448 &retlen, (u_char *)&ctl);
450 if (ret)
451 return ret;
453 xfer->state = XFER_PREPARED;
454 return 0;
456 } /* prepare_xfer */
458 /*======================================================================
460 Copy_erase_unit() takes a full erase block and a transfer unit,
461 copies everything to the transfer unit, then swaps the block
462 pointers.
464 All data blocks are copied to the corresponding blocks in the
465 target unit, so the virtual block map does not need to be
466 updated.
468 ======================================================================*/
470 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
471 u_int16_t xferunit)
473 u_char buf[SECTOR_SIZE];
474 struct eun_info_t *eun;
475 struct xfer_info_t *xfer;
476 u_int32_t src, dest, free, i;
477 u_int16_t unit;
478 int ret;
479 ssize_t retlen;
480 loff_t offset;
481 u_int16_t srcunitswap = cpu_to_le16(srcunit);
483 eun = &part->EUNInfo[srcunit];
484 xfer = &part->XferInfo[xferunit];
485 DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
486 eun->Offset, xfer->Offset);
489 /* Read current BAM */
490 if (part->bam_index != srcunit) {
492 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
494 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
495 part->BlocksPerUnit * sizeof(u_int32_t),
496 &retlen, (u_char *) (part->bam_cache));
498 /* mark the cache bad, in case we get an error later */
499 part->bam_index = 0xffff;
501 if (ret) {
502 printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
503 return ret;
507 /* Write the LogicalEUN for the transfer unit */
508 xfer->state = XFER_UNKNOWN;
509 offset = xfer->Offset + 20; /* Bad! */
510 unit = cpu_to_le16(0x7fff);
512 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
513 &retlen, (u_char *) &unit);
515 if (ret) {
516 printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
517 return ret;
520 /* Copy all data blocks from source unit to transfer unit */
521 src = eun->Offset; dest = xfer->Offset;
523 free = 0;
524 ret = 0;
525 for (i = 0; i < part->BlocksPerUnit; i++) {
526 switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
527 case BLOCK_CONTROL:
528 /* This gets updated later */
529 break;
530 case BLOCK_DATA:
531 case BLOCK_REPLACEMENT:
532 ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
533 &retlen, (u_char *) buf);
534 if (ret) {
535 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
536 return ret;
540 ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
541 &retlen, (u_char *) buf);
542 if (ret) {
543 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
544 return ret;
547 break;
548 default:
549 /* All other blocks must be free */
550 part->bam_cache[i] = cpu_to_le32(0xffffffff);
551 free++;
552 break;
554 src += SECTOR_SIZE;
555 dest += SECTOR_SIZE;
558 /* Write the BAM to the transfer unit */
559 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
560 part->BlocksPerUnit * sizeof(int32_t), &retlen,
561 (u_char *)part->bam_cache);
562 if (ret) {
563 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
564 return ret;
568 /* All clear? Then update the LogicalEUN again */
569 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
570 &retlen, (u_char *)&srcunitswap);
572 if (ret) {
573 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
574 return ret;
578 /* Update the maps and usage stats*/
579 i = xfer->EraseCount;
580 xfer->EraseCount = eun->EraseCount;
581 eun->EraseCount = i;
582 i = xfer->Offset;
583 xfer->Offset = eun->Offset;
584 eun->Offset = i;
585 part->FreeTotal -= eun->Free;
586 part->FreeTotal += free;
587 eun->Free = free;
588 eun->Deleted = 0;
590 /* Now, the cache should be valid for the new block */
591 part->bam_index = srcunit;
593 return 0;
594 } /* copy_erase_unit */
596 /*======================================================================
598 reclaim_block() picks a full erase unit and a transfer unit and
599 then calls copy_erase_unit() to copy one to the other. Then, it
600 schedules an erase on the expired block.
602 What's a good way to decide which transfer unit and which erase
603 unit to use? Beats me. My way is to always pick the transfer
604 unit with the fewest erases, and usually pick the data unit with
605 the most deleted blocks. But with a small probability, pick the
606 oldest data unit instead. This means that we generally postpone
607 the next reclaimation as long as possible, but shuffle static
608 stuff around a bit for wear leveling.
610 ======================================================================*/
612 static int reclaim_block(partition_t *part)
614 u_int16_t i, eun, xfer;
615 u_int32_t best;
616 int queued, ret;
618 DEBUG(0, "ftl_cs: reclaiming space...\n");
619 DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
620 /* Pick the least erased transfer unit */
621 best = 0xffffffff; xfer = 0xffff;
622 do {
623 queued = 0;
624 for (i = 0; i < part->header.NumTransferUnits; i++) {
625 int n=0;
626 if (part->XferInfo[i].state == XFER_UNKNOWN) {
627 DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
628 n=1;
629 erase_xfer(part, i);
631 if (part->XferInfo[i].state == XFER_ERASING) {
632 DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
633 n=1;
634 queued = 1;
636 else if (part->XferInfo[i].state == XFER_ERASED) {
637 DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
638 n=1;
639 prepare_xfer(part, i);
641 if (part->XferInfo[i].state == XFER_PREPARED) {
642 DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
643 n=1;
644 if (part->XferInfo[i].EraseCount <= best) {
645 best = part->XferInfo[i].EraseCount;
646 xfer = i;
649 if (!n)
650 DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
653 if (xfer == 0xffff) {
654 if (queued) {
655 DEBUG(1, "ftl_cs: waiting for transfer "
656 "unit to be prepared...\n");
657 if (part->mbd.mtd->sync)
658 part->mbd.mtd->sync(part->mbd.mtd);
659 } else {
660 static int ne = 0;
661 if (++ne < 5)
662 printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
663 "suitable transfer units!\n");
664 else
665 DEBUG(1, "ftl_cs: reclaim failed: no "
666 "suitable transfer units!\n");
668 return -EIO;
671 } while (xfer == 0xffff);
673 eun = 0;
674 if ((jiffies % shuffle_freq) == 0) {
675 DEBUG(1, "ftl_cs: recycling freshest block...\n");
676 best = 0xffffffff;
677 for (i = 0; i < part->DataUnits; i++)
678 if (part->EUNInfo[i].EraseCount <= best) {
679 best = part->EUNInfo[i].EraseCount;
680 eun = i;
682 } else {
683 best = 0;
684 for (i = 0; i < part->DataUnits; i++)
685 if (part->EUNInfo[i].Deleted >= best) {
686 best = part->EUNInfo[i].Deleted;
687 eun = i;
689 if (best == 0) {
690 static int ne = 0;
691 if (++ne < 5)
692 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
693 "no free blocks!\n");
694 else
695 DEBUG(1,"ftl_cs: reclaim failed: "
696 "no free blocks!\n");
698 return -EIO;
701 ret = copy_erase_unit(part, eun, xfer);
702 if (!ret)
703 erase_xfer(part, xfer);
704 else
705 printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
706 return ret;
707 } /* reclaim_block */
709 /*======================================================================
711 Find_free() searches for a free block. If necessary, it updates
712 the BAM cache for the erase unit containing the free block. It
713 returns the block index -- the erase unit is just the currently
714 cached unit. If there are no free blocks, it returns 0 -- this
715 is never a valid data block because it contains the header.
717 ======================================================================*/
719 #ifdef PSYCHO_DEBUG
720 static void dump_lists(partition_t *part)
722 int i;
723 printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
724 for (i = 0; i < part->DataUnits; i++)
725 printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
726 "%d deleted\n", i,
727 part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
728 part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
730 #endif
732 static u_int32_t find_free(partition_t *part)
734 u_int16_t stop, eun;
735 u_int32_t blk;
736 size_t retlen;
737 int ret;
739 /* Find an erase unit with some free space */
740 stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
741 eun = stop;
742 do {
743 if (part->EUNInfo[eun].Free != 0) break;
744 /* Wrap around at end of table */
745 if (++eun == part->DataUnits) eun = 0;
746 } while (eun != stop);
748 if (part->EUNInfo[eun].Free == 0)
749 return 0;
751 /* Is this unit's BAM cached? */
752 if (eun != part->bam_index) {
753 /* Invalidate cache */
754 part->bam_index = 0xffff;
756 ret = part->mbd.mtd->read(part->mbd.mtd,
757 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
758 part->BlocksPerUnit * sizeof(u_int32_t),
759 &retlen, (u_char *) (part->bam_cache));
761 if (ret) {
762 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
763 return 0;
765 part->bam_index = eun;
768 /* Find a free block */
769 for (blk = 0; blk < part->BlocksPerUnit; blk++)
770 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
771 if (blk == part->BlocksPerUnit) {
772 #ifdef PSYCHO_DEBUG
773 static int ne = 0;
774 if (++ne == 1)
775 dump_lists(part);
776 #endif
777 printk(KERN_NOTICE "ftl_cs: bad free list!\n");
778 return 0;
780 DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
781 return blk;
783 } /* find_free */
786 /*======================================================================
788 Read a series of sectors from an FTL partition.
790 ======================================================================*/
792 static int ftl_read(partition_t *part, caddr_t buffer,
793 u_long sector, u_long nblocks)
795 u_int32_t log_addr, bsize;
796 u_long i;
797 int ret;
798 size_t offset, retlen;
800 DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
801 part, sector, nblocks);
802 if (!(part->state & FTL_FORMATTED)) {
803 printk(KERN_NOTICE "ftl_cs: bad partition\n");
804 return -EIO;
806 bsize = 1 << part->header.EraseUnitSize;
808 for (i = 0; i < nblocks; i++) {
809 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
810 printk(KERN_NOTICE "ftl_cs: bad read offset\n");
811 return -EIO;
813 log_addr = part->VirtualBlockMap[sector+i];
814 if (log_addr == 0xffffffff)
815 memset(buffer, 0, SECTOR_SIZE);
816 else {
817 offset = (part->EUNInfo[log_addr / bsize].Offset
818 + (log_addr % bsize));
819 ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
820 &retlen, (u_char *) buffer);
822 if (ret) {
823 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
824 return ret;
827 buffer += SECTOR_SIZE;
829 return 0;
830 } /* ftl_read */
832 /*======================================================================
834 Write a series of sectors to an FTL partition
836 ======================================================================*/
838 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
839 u_int32_t virt_addr)
841 u_int32_t bsize, blk, le_virt_addr;
842 #ifdef PSYCHO_DEBUG
843 u_int32_t old_addr;
844 #endif
845 u_int16_t eun;
846 int ret;
847 size_t retlen, offset;
849 DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
850 part, log_addr, virt_addr);
851 bsize = 1 << part->header.EraseUnitSize;
852 eun = log_addr / bsize;
853 blk = (log_addr % bsize) / SECTOR_SIZE;
854 offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
855 le32_to_cpu(part->header.BAMOffset));
857 #ifdef PSYCHO_DEBUG
858 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
859 &retlen, (u_char *)&old_addr);
860 if (ret) {
861 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
862 return ret;
864 old_addr = le32_to_cpu(old_addr);
866 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
867 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
868 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
869 static int ne = 0;
870 if (++ne < 5) {
871 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
872 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
873 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
875 return -EIO;
877 #endif
878 le_virt_addr = cpu_to_le32(virt_addr);
879 if (part->bam_index == eun) {
880 #ifdef PSYCHO_DEBUG
881 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
882 static int ne = 0;
883 if (++ne < 5) {
884 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
885 "inconsistency!\n");
886 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
887 " = 0x%x\n",
888 le32_to_cpu(part->bam_cache[blk]), old_addr);
890 return -EIO;
892 #endif
893 part->bam_cache[blk] = le_virt_addr;
895 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
896 &retlen, (u_char *)&le_virt_addr);
898 if (ret) {
899 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
900 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
901 log_addr, virt_addr);
903 return ret;
904 } /* set_bam_entry */
906 static int ftl_write(partition_t *part, caddr_t buffer,
907 u_long sector, u_long nblocks)
909 u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
910 u_long i;
911 int ret;
912 size_t retlen, offset;
914 DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
915 part, sector, nblocks);
916 if (!(part->state & FTL_FORMATTED)) {
917 printk(KERN_NOTICE "ftl_cs: bad partition\n");
918 return -EIO;
920 /* See if we need to reclaim space, before we start */
921 while (part->FreeTotal < nblocks) {
922 ret = reclaim_block(part);
923 if (ret)
924 return ret;
927 bsize = 1 << part->header.EraseUnitSize;
929 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
930 for (i = 0; i < nblocks; i++) {
931 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
932 printk(KERN_NOTICE "ftl_cs: bad write offset\n");
933 return -EIO;
936 /* Grab a free block */
937 blk = find_free(part);
938 if (blk == 0) {
939 static int ne = 0;
940 if (++ne < 5)
941 printk(KERN_NOTICE "ftl_cs: internal error: "
942 "no free blocks!\n");
943 return -ENOSPC;
946 /* Tag the BAM entry, and write the new block */
947 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
948 part->EUNInfo[part->bam_index].Free--;
949 part->FreeTotal--;
950 if (set_bam_entry(part, log_addr, 0xfffffffe))
951 return -EIO;
952 part->EUNInfo[part->bam_index].Deleted++;
953 offset = (part->EUNInfo[part->bam_index].Offset +
954 blk * SECTOR_SIZE);
955 ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
956 buffer);
958 if (ret) {
959 printk(KERN_NOTICE "ftl_cs: block write failed!\n");
960 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
961 " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
962 offset);
963 return -EIO;
966 /* Only delete the old entry when the new entry is ready */
967 old_addr = part->VirtualBlockMap[sector+i];
968 if (old_addr != 0xffffffff) {
969 part->VirtualBlockMap[sector+i] = 0xffffffff;
970 part->EUNInfo[old_addr/bsize].Deleted++;
971 if (set_bam_entry(part, old_addr, 0))
972 return -EIO;
975 /* Finally, set up the new pointers */
976 if (set_bam_entry(part, log_addr, virt_addr))
977 return -EIO;
978 part->VirtualBlockMap[sector+i] = log_addr;
979 part->EUNInfo[part->bam_index].Deleted--;
981 buffer += SECTOR_SIZE;
982 virt_addr += SECTOR_SIZE;
984 return 0;
985 } /* ftl_write */
987 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
989 partition_t *part = (void *)dev;
990 u_long sect;
992 /* Sort of arbitrary: round size down to 4KiB boundary */
993 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
995 geo->heads = 1;
996 geo->sectors = 8;
997 geo->cylinders = sect >> 3;
999 return 0;
1002 static int ftl_readsect(struct mtd_blktrans_dev *dev,
1003 unsigned long block, char *buf)
1005 return ftl_read((void *)dev, buf, block, 1);
1008 static int ftl_writesect(struct mtd_blktrans_dev *dev,
1009 unsigned long block, char *buf)
1011 return ftl_write((void *)dev, buf, block, 1);
1014 /*====================================================================*/
1016 void ftl_freepart(partition_t *part)
1018 if (part->VirtualBlockMap) {
1019 vfree(part->VirtualBlockMap);
1020 part->VirtualBlockMap = NULL;
1022 if (part->VirtualPageMap) {
1023 kfree(part->VirtualPageMap);
1024 part->VirtualPageMap = NULL;
1026 if (part->EUNInfo) {
1027 kfree(part->EUNInfo);
1028 part->EUNInfo = NULL;
1030 if (part->XferInfo) {
1031 kfree(part->XferInfo);
1032 part->XferInfo = NULL;
1034 if (part->bam_cache) {
1035 kfree(part->bam_cache);
1036 part->bam_cache = NULL;
1039 } /* ftl_freepart */
1041 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1043 partition_t *partition;
1045 partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
1047 if (!partition) {
1048 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1049 mtd->name);
1050 return;
1053 memset(partition, 0, sizeof(partition_t));
1055 partition->mbd.mtd = mtd;
1057 if ((scan_header(partition) == 0) &&
1058 (build_maps(partition) == 0)) {
1060 partition->state = FTL_FORMATTED;
1061 #ifdef PCMCIA_DEBUG
1062 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1063 le32_to_cpu(partition->header.FormattedSize) >> 10);
1064 #endif
1065 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1066 partition->mbd.blksize = SECTOR_SIZE;
1067 partition->mbd.tr = tr;
1068 partition->mbd.devnum = -1;
1069 if (add_mtd_blktrans_dev((void *)partition))
1070 kfree(partition);
1072 } else
1073 kfree(partition);
1076 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1078 del_mtd_blktrans_dev(dev);
1079 kfree(dev);
1082 struct mtd_blktrans_ops ftl_tr = {
1083 .name = "ftl",
1084 .major = FTL_MAJOR,
1085 .part_bits = PART_BITS,
1086 .readsect = ftl_readsect,
1087 .writesect = ftl_writesect,
1088 .getgeo = ftl_getgeo,
1089 .add_mtd = ftl_add_mtd,
1090 .remove_dev = ftl_remove_dev,
1091 .owner = THIS_MODULE,
1094 int init_ftl(void)
1096 DEBUG(0, "$Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $\n");
1098 return register_mtd_blktrans(&ftl_tr);
1101 static void __exit cleanup_ftl(void)
1103 deregister_mtd_blktrans(&ftl_tr);
1106 module_init(init_ftl);
1107 module_exit(cleanup_ftl);
1110 MODULE_LICENSE("Dual MPL/GPL");
1111 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1112 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");