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 = part->mbd.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 = part->mbd.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 = part->mbd.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 DEBUG(1, "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 = part->mbd.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 DEBUG(1, "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 = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
426 &retlen, (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 = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t),
442 &retlen, (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 DEBUG(2, "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 = part->mbd.mtd->read(part->mbd.mtd, offset,
489 part->BlocksPerUnit * sizeof(uint32_t),
490 &retlen, (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 = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint16_t),
507 &retlen, (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 = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
527 &retlen, (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 = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
535 &retlen, (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 = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
554 part->BlocksPerUnit * sizeof(int32_t), &retlen,
555 (u_char *)part->bam_cache);
556 if (ret) {
557 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
558 return ret;
559 }
560
561
562 /* All clear? Then update the LogicalEUN again */
563 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
564 &retlen, (u_char *)&srcunitswap);
565
566 if (ret) {
567 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
568 return ret;
569 }
570
571
572 /* Update the maps and usage stats*/
573 i = xfer->EraseCount;
574 xfer->EraseCount = eun->EraseCount;
575 eun->EraseCount = i;
576 i = xfer->Offset;
577 xfer->Offset = eun->Offset;
578 eun->Offset = i;
579 part->FreeTotal -= eun->Free;
580 part->FreeTotal += free;
581 eun->Free = free;
582 eun->Deleted = 0;
583
584 /* Now, the cache should be valid for the new block */
585 part->bam_index = srcunit;
586
587 return 0;
588 } /* copy_erase_unit */
589
590 /*======================================================================
591
592 reclaim_block() picks a full erase unit and a transfer unit and
593 then calls copy_erase_unit() to copy one to the other. Then, it
594 schedules an erase on the expired block.
595
596 What's a good way to decide which transfer unit and which erase
597 unit to use? Beats me. My way is to always pick the transfer
598 unit with the fewest erases, and usually pick the data unit with
599 the most deleted blocks. But with a small probability, pick the
600 oldest data unit instead. This means that we generally postpone
601 the next reclaimation as long as possible, but shuffle static
602 stuff around a bit for wear leveling.
603
604 ======================================================================*/
605
reclaim_block(partition_t * part)606 static int reclaim_block(partition_t *part)
607 {
608 uint16_t i, eun, xfer;
609 uint32_t best;
610 int queued, ret;
611
612 DEBUG(0, "ftl_cs: reclaiming space...\n");
613 DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
614 /* Pick the least erased transfer unit */
615 best = 0xffffffff; xfer = 0xffff;
616 do {
617 queued = 0;
618 for (i = 0; i < part->header.NumTransferUnits; i++) {
619 int n=0;
620 if (part->XferInfo[i].state == XFER_UNKNOWN) {
621 DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
622 n=1;
623 erase_xfer(part, i);
624 }
625 if (part->XferInfo[i].state == XFER_ERASING) {
626 DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
627 n=1;
628 queued = 1;
629 }
630 else if (part->XferInfo[i].state == XFER_ERASED) {
631 DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
632 n=1;
633 prepare_xfer(part, i);
634 }
635 if (part->XferInfo[i].state == XFER_PREPARED) {
636 DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
637 n=1;
638 if (part->XferInfo[i].EraseCount <= best) {
639 best = part->XferInfo[i].EraseCount;
640 xfer = i;
641 }
642 }
643 if (!n)
644 DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
645
646 }
647 if (xfer == 0xffff) {
648 if (queued) {
649 DEBUG(1, "ftl_cs: waiting for transfer "
650 "unit to be prepared...\n");
651 if (part->mbd.mtd->sync)
652 part->mbd.mtd->sync(part->mbd.mtd);
653 } else {
654 static int ne = 0;
655 if (++ne < 5)
656 printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
657 "suitable transfer units!\n");
658 else
659 DEBUG(1, "ftl_cs: reclaim failed: no "
660 "suitable transfer units!\n");
661
662 return -EIO;
663 }
664 }
665 } while (xfer == 0xffff);
666
667 eun = 0;
668 if ((jiffies % shuffle_freq) == 0) {
669 DEBUG(1, "ftl_cs: recycling freshest block...\n");
670 best = 0xffffffff;
671 for (i = 0; i < part->DataUnits; i++)
672 if (part->EUNInfo[i].EraseCount <= best) {
673 best = part->EUNInfo[i].EraseCount;
674 eun = i;
675 }
676 } else {
677 best = 0;
678 for (i = 0; i < part->DataUnits; i++)
679 if (part->EUNInfo[i].Deleted >= best) {
680 best = part->EUNInfo[i].Deleted;
681 eun = i;
682 }
683 if (best == 0) {
684 static int ne = 0;
685 if (++ne < 5)
686 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
687 "no free blocks!\n");
688 else
689 DEBUG(1,"ftl_cs: reclaim failed: "
690 "no free blocks!\n");
691
692 return -EIO;
693 }
694 }
695 ret = copy_erase_unit(part, eun, xfer);
696 if (!ret)
697 erase_xfer(part, xfer);
698 else
699 printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
700 return ret;
701 } /* reclaim_block */
702
703 /*======================================================================
704
705 Find_free() searches for a free block. If necessary, it updates
706 the BAM cache for the erase unit containing the free block. It
707 returns the block index -- the erase unit is just the currently
708 cached unit. If there are no free blocks, it returns 0 -- this
709 is never a valid data block because it contains the header.
710
711 ======================================================================*/
712
713 #ifdef PSYCHO_DEBUG
dump_lists(partition_t * part)714 static void dump_lists(partition_t *part)
715 {
716 int i;
717 printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
718 for (i = 0; i < part->DataUnits; i++)
719 printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
720 "%d deleted\n", i,
721 part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
722 part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
723 }
724 #endif
725
find_free(partition_t * part)726 static uint32_t find_free(partition_t *part)
727 {
728 uint16_t stop, eun;
729 uint32_t blk;
730 size_t retlen;
731 int ret;
732
733 /* Find an erase unit with some free space */
734 stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
735 eun = stop;
736 do {
737 if (part->EUNInfo[eun].Free != 0) break;
738 /* Wrap around at end of table */
739 if (++eun == part->DataUnits) eun = 0;
740 } while (eun != stop);
741
742 if (part->EUNInfo[eun].Free == 0)
743 return 0;
744
745 /* Is this unit's BAM cached? */
746 if (eun != part->bam_index) {
747 /* Invalidate cache */
748 part->bam_index = 0xffff;
749
750 ret = part->mbd.mtd->read(part->mbd.mtd,
751 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
752 part->BlocksPerUnit * sizeof(uint32_t),
753 &retlen, (u_char *) (part->bam_cache));
754
755 if (ret) {
756 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
757 return 0;
758 }
759 part->bam_index = eun;
760 }
761
762 /* Find a free block */
763 for (blk = 0; blk < part->BlocksPerUnit; blk++)
764 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
765 if (blk == part->BlocksPerUnit) {
766 #ifdef PSYCHO_DEBUG
767 static int ne = 0;
768 if (++ne == 1)
769 dump_lists(part);
770 #endif
771 printk(KERN_NOTICE "ftl_cs: bad free list!\n");
772 return 0;
773 }
774 DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
775 return blk;
776
777 } /* find_free */
778
779
780 /*======================================================================
781
782 Read a series of sectors from an FTL partition.
783
784 ======================================================================*/
785
ftl_read(partition_t * part,caddr_t buffer,u_long sector,u_long nblocks)786 static int ftl_read(partition_t *part, caddr_t buffer,
787 u_long sector, u_long nblocks)
788 {
789 uint32_t log_addr, bsize;
790 u_long i;
791 int ret;
792 size_t offset, retlen;
793
794 DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
795 part, sector, nblocks);
796 if (!(part->state & FTL_FORMATTED)) {
797 printk(KERN_NOTICE "ftl_cs: bad partition\n");
798 return -EIO;
799 }
800 bsize = 1 << part->header.EraseUnitSize;
801
802 for (i = 0; i < nblocks; i++) {
803 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
804 printk(KERN_NOTICE "ftl_cs: bad read offset\n");
805 return -EIO;
806 }
807 log_addr = part->VirtualBlockMap[sector+i];
808 if (log_addr == 0xffffffff)
809 memset(buffer, 0, SECTOR_SIZE);
810 else {
811 offset = (part->EUNInfo[log_addr / bsize].Offset
812 + (log_addr % bsize));
813 ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
814 &retlen, (u_char *) buffer);
815
816 if (ret) {
817 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
818 return ret;
819 }
820 }
821 buffer += SECTOR_SIZE;
822 }
823 return 0;
824 } /* ftl_read */
825
826 /*======================================================================
827
828 Write a series of sectors to an FTL partition
829
830 ======================================================================*/
831
set_bam_entry(partition_t * part,uint32_t log_addr,uint32_t virt_addr)832 static int set_bam_entry(partition_t *part, uint32_t log_addr,
833 uint32_t virt_addr)
834 {
835 uint32_t bsize, blk, le_virt_addr;
836 #ifdef PSYCHO_DEBUG
837 uint32_t old_addr;
838 #endif
839 uint16_t eun;
840 int ret;
841 size_t retlen, offset;
842
843 DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
844 part, log_addr, virt_addr);
845 bsize = 1 << part->header.EraseUnitSize;
846 eun = log_addr / bsize;
847 blk = (log_addr % bsize) / SECTOR_SIZE;
848 offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
849 le32_to_cpu(part->header.BAMOffset));
850
851 #ifdef PSYCHO_DEBUG
852 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(uint32_t),
853 &retlen, (u_char *)&old_addr);
854 if (ret) {
855 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
856 return ret;
857 }
858 old_addr = le32_to_cpu(old_addr);
859
860 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
861 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
862 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
863 static int ne = 0;
864 if (++ne < 5) {
865 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
866 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
867 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
868 }
869 return -EIO;
870 }
871 #endif
872 le_virt_addr = cpu_to_le32(virt_addr);
873 if (part->bam_index == eun) {
874 #ifdef PSYCHO_DEBUG
875 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
876 static int ne = 0;
877 if (++ne < 5) {
878 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
879 "inconsistency!\n");
880 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
881 " = 0x%x\n",
882 le32_to_cpu(part->bam_cache[blk]), old_addr);
883 }
884 return -EIO;
885 }
886 #endif
887 part->bam_cache[blk] = le_virt_addr;
888 }
889 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t),
890 &retlen, (u_char *)&le_virt_addr);
891
892 if (ret) {
893 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
894 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
895 log_addr, virt_addr);
896 }
897 return ret;
898 } /* set_bam_entry */
899
ftl_write(partition_t * part,caddr_t buffer,u_long sector,u_long nblocks)900 static int ftl_write(partition_t *part, caddr_t buffer,
901 u_long sector, u_long nblocks)
902 {
903 uint32_t bsize, log_addr, virt_addr, old_addr, blk;
904 u_long i;
905 int ret;
906 size_t retlen, offset;
907
908 DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
909 part, sector, nblocks);
910 if (!(part->state & FTL_FORMATTED)) {
911 printk(KERN_NOTICE "ftl_cs: bad partition\n");
912 return -EIO;
913 }
914 /* See if we need to reclaim space, before we start */
915 while (part->FreeTotal < nblocks) {
916 ret = reclaim_block(part);
917 if (ret)
918 return ret;
919 }
920
921 bsize = 1 << part->header.EraseUnitSize;
922
923 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
924 for (i = 0; i < nblocks; i++) {
925 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
926 printk(KERN_NOTICE "ftl_cs: bad write offset\n");
927 return -EIO;
928 }
929
930 /* Grab a free block */
931 blk = find_free(part);
932 if (blk == 0) {
933 static int ne = 0;
934 if (++ne < 5)
935 printk(KERN_NOTICE "ftl_cs: internal error: "
936 "no free blocks!\n");
937 return -ENOSPC;
938 }
939
940 /* Tag the BAM entry, and write the new block */
941 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
942 part->EUNInfo[part->bam_index].Free--;
943 part->FreeTotal--;
944 if (set_bam_entry(part, log_addr, 0xfffffffe))
945 return -EIO;
946 part->EUNInfo[part->bam_index].Deleted++;
947 offset = (part->EUNInfo[part->bam_index].Offset +
948 blk * SECTOR_SIZE);
949 ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
950 buffer);
951
952 if (ret) {
953 printk(KERN_NOTICE "ftl_cs: block write failed!\n");
954 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
955 " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
956 offset);
957 return -EIO;
958 }
959
960 /* Only delete the old entry when the new entry is ready */
961 old_addr = part->VirtualBlockMap[sector+i];
962 if (old_addr != 0xffffffff) {
963 part->VirtualBlockMap[sector+i] = 0xffffffff;
964 part->EUNInfo[old_addr/bsize].Deleted++;
965 if (set_bam_entry(part, old_addr, 0))
966 return -EIO;
967 }
968
969 /* Finally, set up the new pointers */
970 if (set_bam_entry(part, log_addr, virt_addr))
971 return -EIO;
972 part->VirtualBlockMap[sector+i] = log_addr;
973 part->EUNInfo[part->bam_index].Deleted--;
974
975 buffer += SECTOR_SIZE;
976 virt_addr += SECTOR_SIZE;
977 }
978 return 0;
979 } /* ftl_write */
980
ftl_getgeo(struct mtd_blktrans_dev * dev,struct hd_geometry * geo)981 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
982 {
983 partition_t *part = (void *)dev;
984 u_long sect;
985
986 /* Sort of arbitrary: round size down to 4KiB boundary */
987 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
988
989 geo->heads = 1;
990 geo->sectors = 8;
991 geo->cylinders = sect >> 3;
992
993 return 0;
994 }
995
ftl_readsect(struct mtd_blktrans_dev * dev,unsigned long block,char * buf)996 static int ftl_readsect(struct mtd_blktrans_dev *dev,
997 unsigned long block, char *buf)
998 {
999 return ftl_read((void *)dev, buf, block, 1);
1000 }
1001
ftl_writesect(struct mtd_blktrans_dev * dev,unsigned long block,char * buf)1002 static int ftl_writesect(struct mtd_blktrans_dev *dev,
1003 unsigned long block, char *buf)
1004 {
1005 return ftl_write((void *)dev, buf, block, 1);
1006 }
1007
ftl_discardsect(struct mtd_blktrans_dev * dev,unsigned long sector,unsigned nr_sects)1008 static int ftl_discardsect(struct mtd_blktrans_dev *dev,
1009 unsigned long sector, unsigned nr_sects)
1010 {
1011 partition_t *part = (void *)dev;
1012 uint32_t bsize = 1 << part->header.EraseUnitSize;
1013
1014 DEBUG(1, "FTL erase sector %ld for %d sectors\n",
1015 sector, nr_sects);
1016
1017 while (nr_sects) {
1018 uint32_t old_addr = part->VirtualBlockMap[sector];
1019 if (old_addr != 0xffffffff) {
1020 part->VirtualBlockMap[sector] = 0xffffffff;
1021 part->EUNInfo[old_addr/bsize].Deleted++;
1022 if (set_bam_entry(part, old_addr, 0))
1023 return -EIO;
1024 }
1025 nr_sects--;
1026 sector++;
1027 }
1028
1029 return 0;
1030 }
1031 /*====================================================================*/
1032
ftl_freepart(partition_t * part)1033 static void ftl_freepart(partition_t *part)
1034 {
1035 vfree(part->VirtualBlockMap);
1036 part->VirtualBlockMap = NULL;
1037 kfree(part->VirtualPageMap);
1038 part->VirtualPageMap = NULL;
1039 kfree(part->EUNInfo);
1040 part->EUNInfo = NULL;
1041 kfree(part->XferInfo);
1042 part->XferInfo = NULL;
1043 kfree(part->bam_cache);
1044 part->bam_cache = NULL;
1045 } /* ftl_freepart */
1046
ftl_add_mtd(struct mtd_blktrans_ops * tr,struct mtd_info * mtd)1047 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1048 {
1049 partition_t *partition;
1050
1051 partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1052
1053 if (!partition) {
1054 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1055 mtd->name);
1056 return;
1057 }
1058
1059 partition->mbd.mtd = mtd;
1060
1061 if ((scan_header(partition) == 0) &&
1062 (build_maps(partition) == 0)) {
1063
1064 partition->state = FTL_FORMATTED;
1065 #ifdef PCMCIA_DEBUG
1066 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1067 le32_to_cpu(partition->header.FormattedSize) >> 10);
1068 #endif
1069 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1070
1071 partition->mbd.tr = tr;
1072 partition->mbd.devnum = -1;
1073 if (!add_mtd_blktrans_dev((void *)partition))
1074 return;
1075 }
1076
1077 ftl_freepart(partition);
1078 kfree(partition);
1079 }
1080
ftl_remove_dev(struct mtd_blktrans_dev * dev)1081 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1082 {
1083 del_mtd_blktrans_dev(dev);
1084 ftl_freepart((partition_t *)dev);
1085 }
1086
1087 static struct mtd_blktrans_ops ftl_tr = {
1088 .name = "ftl",
1089 .major = FTL_MAJOR,
1090 .part_bits = PART_BITS,
1091 .blksize = SECTOR_SIZE,
1092 .readsect = ftl_readsect,
1093 .writesect = ftl_writesect,
1094 .discard = ftl_discardsect,
1095 .getgeo = ftl_getgeo,
1096 .add_mtd = ftl_add_mtd,
1097 .remove_dev = ftl_remove_dev,
1098 .owner = THIS_MODULE,
1099 };
1100
init_ftl(void)1101 static int __init init_ftl(void)
1102 {
1103 return register_mtd_blktrans(&ftl_tr);
1104 }
1105
cleanup_ftl(void)1106 static void __exit cleanup_ftl(void)
1107 {
1108 deregister_mtd_blktrans(&ftl_tr);
1109 }
1110
1111 module_init(init_ftl);
1112 module_exit(cleanup_ftl);
1113
1114
1115 MODULE_LICENSE("Dual MPL/GPL");
1116 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1117 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
1118