[MIPS] remove machtype for group Toshiba
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / mtd / ftl.c
blob5c29872184e65b64c3f5938968aaeb29061601f6
1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2 * $Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner 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/ptrace.h>
65 #include <linux/slab.h>
66 #include <linux/string.h>
67 #include <linux/timer.h>
68 #include <linux/major.h>
69 #include <linux/fs.h>
70 #include <linux/init.h>
71 #include <linux/hdreg.h>
72 #include <linux/vmalloc.h>
73 #include <linux/blkpg.h>
74 #include <asm/uaccess.h>
76 #include <linux/mtd/ftl.h>
78 /*====================================================================*/
80 /* Parameters that can be set with 'insmod' */
81 static int shuffle_freq = 50;
82 module_param(shuffle_freq, int, 0);
84 /*====================================================================*/
86 /* Major device # for FTL device */
87 #ifndef FTL_MAJOR
88 #define FTL_MAJOR 44
89 #endif
92 /*====================================================================*/
94 /* Maximum number of separate memory devices we'll allow */
95 #define MAX_DEV 4
97 /* Maximum number of regions per device */
98 #define MAX_REGION 4
100 /* Maximum number of partitions in an FTL region */
101 #define PART_BITS 4
103 /* Maximum number of outstanding erase requests per socket */
104 #define MAX_ERASE 8
106 /* Sector size -- shouldn't need to change */
107 #define SECTOR_SIZE 512
110 /* Each memory region corresponds to a minor device */
111 typedef struct partition_t {
112 struct mtd_blktrans_dev mbd;
113 u_int32_t state;
114 u_int32_t *VirtualBlockMap;
115 u_int32_t *VirtualPageMap;
116 u_int32_t FreeTotal;
117 struct eun_info_t {
118 u_int32_t Offset;
119 u_int32_t EraseCount;
120 u_int32_t Free;
121 u_int32_t Deleted;
122 } *EUNInfo;
123 struct xfer_info_t {
124 u_int32_t Offset;
125 u_int32_t EraseCount;
126 u_int16_t state;
127 } *XferInfo;
128 u_int16_t bam_index;
129 u_int32_t *bam_cache;
130 u_int16_t DataUnits;
131 u_int32_t BlocksPerUnit;
132 erase_unit_header_t header;
133 } partition_t;
135 /* Partition state flags */
136 #define FTL_FORMATTED 0x01
138 /* Transfer unit states */
139 #define XFER_UNKNOWN 0x00
140 #define XFER_ERASING 0x01
141 #define XFER_ERASED 0x02
142 #define XFER_PREPARED 0x03
143 #define XFER_FAILED 0x04
145 /*====================================================================*/
148 static void ftl_erase_callback(struct erase_info *done);
151 /*======================================================================
153 Scan_header() checks to see if a memory region contains an FTL
154 partition. build_maps() reads all the erase unit headers, builds
155 the erase unit map, and then builds the virtual page map.
157 ======================================================================*/
159 static int scan_header(partition_t *part)
161 erase_unit_header_t header;
162 loff_t offset, max_offset;
163 size_t ret;
164 int err;
165 part->header.FormattedSize = 0;
166 max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
167 /* Search first megabyte for a valid FTL header */
168 for (offset = 0;
169 (offset + sizeof(header)) < max_offset;
170 offset += part->mbd.mtd->erasesize ? : 0x2000) {
172 err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
173 (unsigned char *)&header);
175 if (err)
176 return err;
178 if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
181 if (offset == max_offset) {
182 printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
183 return -ENOENT;
185 if (header.BlockSize != 9 ||
186 (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
187 (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
188 printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
189 return -1;
191 if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
192 printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
193 1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
194 return -1;
196 part->header = header;
197 return 0;
200 static int build_maps(partition_t *part)
202 erase_unit_header_t header;
203 u_int16_t xvalid, xtrans, i;
204 u_int blocks, j;
205 int hdr_ok, ret = -1;
206 ssize_t retval;
207 loff_t offset;
209 /* Set up erase unit maps */
210 part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
211 part->header.NumTransferUnits;
212 part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
213 GFP_KERNEL);
214 if (!part->EUNInfo)
215 goto out;
216 for (i = 0; i < part->DataUnits; i++)
217 part->EUNInfo[i].Offset = 0xffffffff;
218 part->XferInfo =
219 kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
220 GFP_KERNEL);
221 if (!part->XferInfo)
222 goto out_EUNInfo;
224 xvalid = xtrans = 0;
225 for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
226 offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
227 << part->header.EraseUnitSize);
228 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
229 (unsigned char *)&header);
231 if (ret)
232 goto out_XferInfo;
234 ret = -1;
235 /* Is this a transfer partition? */
236 hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
237 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
238 (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
239 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
240 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
241 le32_to_cpu(header.EraseCount);
242 xvalid++;
243 } else {
244 if (xtrans == part->header.NumTransferUnits) {
245 printk(KERN_NOTICE "ftl_cs: format error: too many "
246 "transfer units!\n");
247 goto out_XferInfo;
249 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
250 part->XferInfo[xtrans].state = XFER_PREPARED;
251 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
252 } else {
253 part->XferInfo[xtrans].state = XFER_UNKNOWN;
254 /* Pick anything reasonable for the erase count */
255 part->XferInfo[xtrans].EraseCount =
256 le32_to_cpu(part->header.EraseCount);
258 part->XferInfo[xtrans].Offset = offset;
259 xtrans++;
262 /* Check for format trouble */
263 header = part->header;
264 if ((xtrans != header.NumTransferUnits) ||
265 (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
266 printk(KERN_NOTICE "ftl_cs: format error: erase units "
267 "don't add up!\n");
268 goto out_XferInfo;
271 /* Set up virtual page map */
272 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
273 part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
274 if (!part->VirtualBlockMap)
275 goto out_XferInfo;
277 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
278 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
280 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
281 GFP_KERNEL);
282 if (!part->bam_cache)
283 goto out_VirtualBlockMap;
285 part->bam_index = 0xffff;
286 part->FreeTotal = 0;
288 for (i = 0; i < part->DataUnits; i++) {
289 part->EUNInfo[i].Free = 0;
290 part->EUNInfo[i].Deleted = 0;
291 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
293 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
294 part->BlocksPerUnit * sizeof(u_int32_t), &retval,
295 (unsigned char *)part->bam_cache);
297 if (ret)
298 goto out_bam_cache;
300 for (j = 0; j < part->BlocksPerUnit; j++) {
301 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
302 part->EUNInfo[i].Free++;
303 part->FreeTotal++;
304 } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
305 (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
306 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
307 (i << header.EraseUnitSize) + (j << header.BlockSize);
308 else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
309 part->EUNInfo[i].Deleted++;
313 ret = 0;
314 goto out;
316 out_bam_cache:
317 kfree(part->bam_cache);
318 out_VirtualBlockMap:
319 vfree(part->VirtualBlockMap);
320 out_XferInfo:
321 kfree(part->XferInfo);
322 out_EUNInfo:
323 kfree(part->EUNInfo);
324 out:
325 return ret;
326 } /* build_maps */
328 /*======================================================================
330 Erase_xfer() schedules an asynchronous erase operation for a
331 transfer unit.
333 ======================================================================*/
335 static int erase_xfer(partition_t *part,
336 u_int16_t xfernum)
338 int ret;
339 struct xfer_info_t *xfer;
340 struct erase_info *erase;
342 xfer = &part->XferInfo[xfernum];
343 DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
344 xfer->state = XFER_ERASING;
346 /* Is there a free erase slot? Always in MTD. */
349 erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
350 if (!erase)
351 return -ENOMEM;
353 erase->mtd = part->mbd.mtd;
354 erase->callback = ftl_erase_callback;
355 erase->addr = xfer->Offset;
356 erase->len = 1 << part->header.EraseUnitSize;
357 erase->priv = (u_long)part;
359 ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
361 if (!ret)
362 xfer->EraseCount++;
363 else
364 kfree(erase);
366 return ret;
367 } /* erase_xfer */
369 /*======================================================================
371 Prepare_xfer() takes a freshly erased transfer unit and gives
372 it an appropriate header.
374 ======================================================================*/
376 static void ftl_erase_callback(struct erase_info *erase)
378 partition_t *part;
379 struct xfer_info_t *xfer;
380 int i;
382 /* Look up the transfer unit */
383 part = (partition_t *)(erase->priv);
385 for (i = 0; i < part->header.NumTransferUnits; i++)
386 if (part->XferInfo[i].Offset == erase->addr) break;
388 if (i == part->header.NumTransferUnits) {
389 printk(KERN_NOTICE "ftl_cs: internal error: "
390 "erase lookup failed!\n");
391 return;
394 xfer = &part->XferInfo[i];
395 if (erase->state == MTD_ERASE_DONE)
396 xfer->state = XFER_ERASED;
397 else {
398 xfer->state = XFER_FAILED;
399 printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
400 erase->state);
403 kfree(erase);
405 } /* ftl_erase_callback */
407 static int prepare_xfer(partition_t *part, int i)
409 erase_unit_header_t header;
410 struct xfer_info_t *xfer;
411 int nbam, ret;
412 u_int32_t ctl;
413 ssize_t retlen;
414 loff_t offset;
416 xfer = &part->XferInfo[i];
417 xfer->state = XFER_FAILED;
419 DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
421 /* Write the transfer unit header */
422 header = part->header;
423 header.LogicalEUN = cpu_to_le16(0xffff);
424 header.EraseCount = cpu_to_le32(xfer->EraseCount);
426 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
427 &retlen, (u_char *)&header);
429 if (ret) {
430 return ret;
433 /* Write the BAM stub */
434 nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
435 le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
437 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
438 ctl = cpu_to_le32(BLOCK_CONTROL);
440 for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
442 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
443 &retlen, (u_char *)&ctl);
445 if (ret)
446 return ret;
448 xfer->state = XFER_PREPARED;
449 return 0;
451 } /* prepare_xfer */
453 /*======================================================================
455 Copy_erase_unit() takes a full erase block and a transfer unit,
456 copies everything to the transfer unit, then swaps the block
457 pointers.
459 All data blocks are copied to the corresponding blocks in the
460 target unit, so the virtual block map does not need to be
461 updated.
463 ======================================================================*/
465 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
466 u_int16_t xferunit)
468 u_char buf[SECTOR_SIZE];
469 struct eun_info_t *eun;
470 struct xfer_info_t *xfer;
471 u_int32_t src, dest, free, i;
472 u_int16_t unit;
473 int ret;
474 ssize_t retlen;
475 loff_t offset;
476 u_int16_t srcunitswap = cpu_to_le16(srcunit);
478 eun = &part->EUNInfo[srcunit];
479 xfer = &part->XferInfo[xferunit];
480 DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
481 eun->Offset, xfer->Offset);
484 /* Read current BAM */
485 if (part->bam_index != srcunit) {
487 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
489 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
490 part->BlocksPerUnit * sizeof(u_int32_t),
491 &retlen, (u_char *) (part->bam_cache));
493 /* mark the cache bad, in case we get an error later */
494 part->bam_index = 0xffff;
496 if (ret) {
497 printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
498 return ret;
502 /* Write the LogicalEUN for the transfer unit */
503 xfer->state = XFER_UNKNOWN;
504 offset = xfer->Offset + 20; /* Bad! */
505 unit = cpu_to_le16(0x7fff);
507 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
508 &retlen, (u_char *) &unit);
510 if (ret) {
511 printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
512 return ret;
515 /* Copy all data blocks from source unit to transfer unit */
516 src = eun->Offset; dest = xfer->Offset;
518 free = 0;
519 ret = 0;
520 for (i = 0; i < part->BlocksPerUnit; i++) {
521 switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
522 case BLOCK_CONTROL:
523 /* This gets updated later */
524 break;
525 case BLOCK_DATA:
526 case BLOCK_REPLACEMENT:
527 ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
528 &retlen, (u_char *) buf);
529 if (ret) {
530 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
531 return ret;
535 ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
536 &retlen, (u_char *) buf);
537 if (ret) {
538 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
539 return ret;
542 break;
543 default:
544 /* All other blocks must be free */
545 part->bam_cache[i] = cpu_to_le32(0xffffffff);
546 free++;
547 break;
549 src += SECTOR_SIZE;
550 dest += SECTOR_SIZE;
553 /* Write the BAM to the transfer unit */
554 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
555 part->BlocksPerUnit * sizeof(int32_t), &retlen,
556 (u_char *)part->bam_cache);
557 if (ret) {
558 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
559 return ret;
563 /* All clear? Then update the LogicalEUN again */
564 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
565 &retlen, (u_char *)&srcunitswap);
567 if (ret) {
568 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
569 return ret;
573 /* Update the maps and usage stats*/
574 i = xfer->EraseCount;
575 xfer->EraseCount = eun->EraseCount;
576 eun->EraseCount = i;
577 i = xfer->Offset;
578 xfer->Offset = eun->Offset;
579 eun->Offset = i;
580 part->FreeTotal -= eun->Free;
581 part->FreeTotal += free;
582 eun->Free = free;
583 eun->Deleted = 0;
585 /* Now, the cache should be valid for the new block */
586 part->bam_index = srcunit;
588 return 0;
589 } /* copy_erase_unit */
591 /*======================================================================
593 reclaim_block() picks a full erase unit and a transfer unit and
594 then calls copy_erase_unit() to copy one to the other. Then, it
595 schedules an erase on the expired block.
597 What's a good way to decide which transfer unit and which erase
598 unit to use? Beats me. My way is to always pick the transfer
599 unit with the fewest erases, and usually pick the data unit with
600 the most deleted blocks. But with a small probability, pick the
601 oldest data unit instead. This means that we generally postpone
602 the next reclaimation as long as possible, but shuffle static
603 stuff around a bit for wear leveling.
605 ======================================================================*/
607 static int reclaim_block(partition_t *part)
609 u_int16_t i, eun, xfer;
610 u_int32_t best;
611 int queued, ret;
613 DEBUG(0, "ftl_cs: reclaiming space...\n");
614 DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
615 /* Pick the least erased transfer unit */
616 best = 0xffffffff; xfer = 0xffff;
617 do {
618 queued = 0;
619 for (i = 0; i < part->header.NumTransferUnits; i++) {
620 int n=0;
621 if (part->XferInfo[i].state == XFER_UNKNOWN) {
622 DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
623 n=1;
624 erase_xfer(part, i);
626 if (part->XferInfo[i].state == XFER_ERASING) {
627 DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
628 n=1;
629 queued = 1;
631 else if (part->XferInfo[i].state == XFER_ERASED) {
632 DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
633 n=1;
634 prepare_xfer(part, i);
636 if (part->XferInfo[i].state == XFER_PREPARED) {
637 DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
638 n=1;
639 if (part->XferInfo[i].EraseCount <= best) {
640 best = part->XferInfo[i].EraseCount;
641 xfer = i;
644 if (!n)
645 DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
648 if (xfer == 0xffff) {
649 if (queued) {
650 DEBUG(1, "ftl_cs: waiting for transfer "
651 "unit to be prepared...\n");
652 if (part->mbd.mtd->sync)
653 part->mbd.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 DEBUG(1, "ftl_cs: reclaim failed: no "
661 "suitable transfer units!\n");
663 return -EIO;
666 } while (xfer == 0xffff);
668 eun = 0;
669 if ((jiffies % shuffle_freq) == 0) {
670 DEBUG(1, "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;
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;
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 DEBUG(1,"ftl_cs: reclaim failed: "
691 "no free blocks!\n");
693 return -EIO;
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 */
704 /*======================================================================
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.
712 ======================================================================*/
714 #ifdef PSYCHO_DEBUG
715 static void dump_lists(partition_t *part)
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);
725 #endif
727 static u_int32_t find_free(partition_t *part)
729 u_int16_t stop, eun;
730 u_int32_t blk;
731 size_t retlen;
732 int ret;
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);
743 if (part->EUNInfo[eun].Free == 0)
744 return 0;
746 /* Is this unit's BAM cached? */
747 if (eun != part->bam_index) {
748 /* Invalidate cache */
749 part->bam_index = 0xffff;
751 ret = part->mbd.mtd->read(part->mbd.mtd,
752 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
753 part->BlocksPerUnit * sizeof(u_int32_t),
754 &retlen, (u_char *) (part->bam_cache));
756 if (ret) {
757 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
758 return 0;
760 part->bam_index = eun;
763 /* Find a free block */
764 for (blk = 0; blk < part->BlocksPerUnit; blk++)
765 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
766 if (blk == part->BlocksPerUnit) {
767 #ifdef PSYCHO_DEBUG
768 static int ne = 0;
769 if (++ne == 1)
770 dump_lists(part);
771 #endif
772 printk(KERN_NOTICE "ftl_cs: bad free list!\n");
773 return 0;
775 DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
776 return blk;
778 } /* find_free */
781 /*======================================================================
783 Read a series of sectors from an FTL partition.
785 ======================================================================*/
787 static int ftl_read(partition_t *part, caddr_t buffer,
788 u_long sector, u_long nblocks)
790 u_int32_t log_addr, bsize;
791 u_long i;
792 int ret;
793 size_t offset, retlen;
795 DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
796 part, sector, nblocks);
797 if (!(part->state & FTL_FORMATTED)) {
798 printk(KERN_NOTICE "ftl_cs: bad partition\n");
799 return -EIO;
801 bsize = 1 << part->header.EraseUnitSize;
803 for (i = 0; i < nblocks; i++) {
804 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
805 printk(KERN_NOTICE "ftl_cs: bad read offset\n");
806 return -EIO;
808 log_addr = part->VirtualBlockMap[sector+i];
809 if (log_addr == 0xffffffff)
810 memset(buffer, 0, SECTOR_SIZE);
811 else {
812 offset = (part->EUNInfo[log_addr / bsize].Offset
813 + (log_addr % bsize));
814 ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
815 &retlen, (u_char *) buffer);
817 if (ret) {
818 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
819 return ret;
822 buffer += SECTOR_SIZE;
824 return 0;
825 } /* ftl_read */
827 /*======================================================================
829 Write a series of sectors to an FTL partition
831 ======================================================================*/
833 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
834 u_int32_t virt_addr)
836 u_int32_t bsize, blk, le_virt_addr;
837 #ifdef PSYCHO_DEBUG
838 u_int32_t old_addr;
839 #endif
840 u_int16_t eun;
841 int ret;
842 size_t retlen, offset;
844 DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
845 part, log_addr, virt_addr);
846 bsize = 1 << part->header.EraseUnitSize;
847 eun = log_addr / bsize;
848 blk = (log_addr % bsize) / SECTOR_SIZE;
849 offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
850 le32_to_cpu(part->header.BAMOffset));
852 #ifdef PSYCHO_DEBUG
853 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
854 &retlen, (u_char *)&old_addr);
855 if (ret) {
856 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
857 return ret;
859 old_addr = le32_to_cpu(old_addr);
861 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
862 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
863 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
864 static int ne = 0;
865 if (++ne < 5) {
866 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
867 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
868 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
870 return -EIO;
872 #endif
873 le_virt_addr = cpu_to_le32(virt_addr);
874 if (part->bam_index == eun) {
875 #ifdef PSYCHO_DEBUG
876 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
877 static int ne = 0;
878 if (++ne < 5) {
879 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
880 "inconsistency!\n");
881 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
882 " = 0x%x\n",
883 le32_to_cpu(part->bam_cache[blk]), old_addr);
885 return -EIO;
887 #endif
888 part->bam_cache[blk] = le_virt_addr;
890 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
891 &retlen, (u_char *)&le_virt_addr);
893 if (ret) {
894 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
895 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
896 log_addr, virt_addr);
898 return ret;
899 } /* set_bam_entry */
901 static int ftl_write(partition_t *part, caddr_t buffer,
902 u_long sector, u_long nblocks)
904 u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
905 u_long i;
906 int ret;
907 size_t retlen, offset;
909 DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
910 part, sector, nblocks);
911 if (!(part->state & FTL_FORMATTED)) {
912 printk(KERN_NOTICE "ftl_cs: bad partition\n");
913 return -EIO;
915 /* See if we need to reclaim space, before we start */
916 while (part->FreeTotal < nblocks) {
917 ret = reclaim_block(part);
918 if (ret)
919 return ret;
922 bsize = 1 << part->header.EraseUnitSize;
924 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
925 for (i = 0; i < nblocks; i++) {
926 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
927 printk(KERN_NOTICE "ftl_cs: bad write offset\n");
928 return -EIO;
931 /* Grab a free block */
932 blk = find_free(part);
933 if (blk == 0) {
934 static int ne = 0;
935 if (++ne < 5)
936 printk(KERN_NOTICE "ftl_cs: internal error: "
937 "no free blocks!\n");
938 return -ENOSPC;
941 /* Tag the BAM entry, and write the new block */
942 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
943 part->EUNInfo[part->bam_index].Free--;
944 part->FreeTotal--;
945 if (set_bam_entry(part, log_addr, 0xfffffffe))
946 return -EIO;
947 part->EUNInfo[part->bam_index].Deleted++;
948 offset = (part->EUNInfo[part->bam_index].Offset +
949 blk * SECTOR_SIZE);
950 ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
951 buffer);
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;
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;
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--;
976 buffer += SECTOR_SIZE;
977 virt_addr += SECTOR_SIZE;
979 return 0;
980 } /* ftl_write */
982 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
984 partition_t *part = (void *)dev;
985 u_long sect;
987 /* Sort of arbitrary: round size down to 4KiB boundary */
988 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
990 geo->heads = 1;
991 geo->sectors = 8;
992 geo->cylinders = sect >> 3;
994 return 0;
997 static int ftl_readsect(struct mtd_blktrans_dev *dev,
998 unsigned long block, char *buf)
1000 return ftl_read((void *)dev, buf, block, 1);
1003 static int ftl_writesect(struct mtd_blktrans_dev *dev,
1004 unsigned long block, char *buf)
1006 return ftl_write((void *)dev, buf, block, 1);
1009 /*====================================================================*/
1011 static void ftl_freepart(partition_t *part)
1013 vfree(part->VirtualBlockMap);
1014 part->VirtualBlockMap = NULL;
1015 kfree(part->VirtualPageMap);
1016 part->VirtualPageMap = NULL;
1017 kfree(part->EUNInfo);
1018 part->EUNInfo = NULL;
1019 kfree(part->XferInfo);
1020 part->XferInfo = NULL;
1021 kfree(part->bam_cache);
1022 part->bam_cache = NULL;
1023 } /* ftl_freepart */
1025 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1027 partition_t *partition;
1029 partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1031 if (!partition) {
1032 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1033 mtd->name);
1034 return;
1037 partition->mbd.mtd = mtd;
1039 if ((scan_header(partition) == 0) &&
1040 (build_maps(partition) == 0)) {
1042 partition->state = FTL_FORMATTED;
1043 #ifdef PCMCIA_DEBUG
1044 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1045 le32_to_cpu(partition->header.FormattedSize) >> 10);
1046 #endif
1047 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1049 partition->mbd.tr = tr;
1050 partition->mbd.devnum = -1;
1051 if (!add_mtd_blktrans_dev((void *)partition))
1052 return;
1055 ftl_freepart(partition);
1056 kfree(partition);
1059 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1061 del_mtd_blktrans_dev(dev);
1062 ftl_freepart((partition_t *)dev);
1063 kfree(dev);
1066 static struct mtd_blktrans_ops ftl_tr = {
1067 .name = "ftl",
1068 .major = FTL_MAJOR,
1069 .part_bits = PART_BITS,
1070 .blksize = SECTOR_SIZE,
1071 .readsect = ftl_readsect,
1072 .writesect = ftl_writesect,
1073 .getgeo = ftl_getgeo,
1074 .add_mtd = ftl_add_mtd,
1075 .remove_dev = ftl_remove_dev,
1076 .owner = THIS_MODULE,
1079 static int init_ftl(void)
1081 DEBUG(0, "$Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $\n");
1083 return register_mtd_blktrans(&ftl_tr);
1086 static void __exit cleanup_ftl(void)
1088 deregister_mtd_blktrans(&ftl_tr);
1091 module_init(init_ftl);
1092 module_exit(cleanup_ftl);
1095 MODULE_LICENSE("Dual MPL/GPL");
1096 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1097 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");