[PATCH] m68k: bitops update [3/20]
[linux-2.6/history.git] / drivers / mtd / ftl.c
blob889164aac0df714faf7e9dd0b8635fb3041f5e61
1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
2 * $Id: ftl.c,v 1.39 2001/10/02 15:05:11 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 <dhinds@pcmcia.sourceforge.org>. 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/module.h>
59 #include <linux/mtd/compatmac.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/ioctl.h>
72 #include <linux/hdreg.h>
73 #include <stdarg.h>
75 #include <linux/vmalloc.h>
76 #include <linux/blkpg.h>
78 #include <linux/mtd/ftl.h>
80 #define request_arg_t request_queue_t *q
82 /*====================================================================*/
84 /* Parameters that can be set with 'insmod' */
85 static int shuffle_freq = 50;
86 MODULE_PARM(shuffle_freq, "i");
88 /*====================================================================*/
90 /* Major device # for FTL device */
91 #ifndef FTL_MAJOR
92 #define FTL_MAJOR 44
93 #endif
95 /* Funky stuff for setting up a block device */
96 #define MAJOR_NR FTL_MAJOR
97 #define DEVICE_NAME "ftl"
98 #define DEVICE_OFF(device)
100 #define DEVICE_NR(minor) ((minor)>>5)
101 #define REGION_NR(minor) (((minor)>>3)&3)
102 #define PART_NR(minor) ((minor)&7)
103 #define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part))
105 #include <linux/blk.h>
107 /*====================================================================*/
109 /* Maximum number of separate memory devices we'll allow */
110 #define MAX_DEV 4
112 /* Maximum number of regions per device */
113 #define MAX_REGION 4
115 /* Maximum number of partitions in an FTL region */
116 #define PART_BITS 3
117 #define MAX_PART 8
119 /* Maximum number of outstanding erase requests per socket */
120 #define MAX_ERASE 8
122 /* Sector size -- shouldn't need to change */
123 #define SECTOR_SIZE 512
126 /* Each memory region corresponds to a minor device */
127 typedef struct partition_t {
128 struct mtd_info *mtd;
129 u_int32_t state;
130 u_int32_t *VirtualBlockMap;
131 u_int32_t *VirtualPageMap;
132 u_int32_t FreeTotal;
133 struct eun_info_t {
134 u_int32_t Offset;
135 u_int32_t EraseCount;
136 u_int32_t Free;
137 u_int32_t Deleted;
138 } *EUNInfo;
139 struct xfer_info_t {
140 u_int32_t Offset;
141 u_int32_t EraseCount;
142 u_int16_t state;
143 } *XferInfo;
144 u_int16_t bam_index;
145 u_int32_t *bam_cache;
146 u_int16_t DataUnits;
147 u_int32_t BlocksPerUnit;
148 erase_unit_header_t header;
149 #if 0
150 region_info_t region;
151 memory_handle_t handle;
152 #endif
153 atomic_t open;
154 } partition_t;
156 partition_t *myparts[MAX_MTD_DEVICES];
158 static void ftl_notify_add(struct mtd_info *mtd);
159 static void ftl_notify_remove(struct mtd_info *mtd);
161 void ftl_freepart(partition_t *part);
163 static struct mtd_notifier ftl_notifier = {
164 add: ftl_notify_add,
165 remove: ftl_notify_remove,
168 /* Partition state flags */
169 #define FTL_FORMATTED 0x01
171 /* Transfer unit states */
172 #define XFER_UNKNOWN 0x00
173 #define XFER_ERASING 0x01
174 #define XFER_ERASED 0x02
175 #define XFER_PREPARED 0x03
176 #define XFER_FAILED 0x04
178 static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
179 static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
181 static struct gendisk ftl_gendisk = {
182 major: FTL_MAJOR,
183 major_name: "ftl",
184 minor_shift: PART_BITS,
185 part: ftl_hd,
186 sizes: ftl_sizes,
189 /*====================================================================*/
191 static int ftl_ioctl(struct inode *inode, struct file *file,
192 u_int cmd, u_long arg);
193 static int ftl_open(struct inode *inode, struct file *file);
194 static release_t ftl_close(struct inode *inode, struct file *file);
195 static int ftl_reread_partitions(kdev_t dev);
197 static void ftl_erase_callback(struct erase_info *done);
199 static struct block_device_operations ftl_blk_fops = {
200 owner: THIS_MODULE,
201 open: ftl_open,
202 release: ftl_close,
203 ioctl: ftl_ioctl,
206 /*======================================================================
208 Scan_header() checks to see if a memory region contains an FTL
209 partition. build_maps() reads all the erase unit headers, builds
210 the erase unit map, and then builds the virtual page map.
212 ======================================================================*/
214 static int scan_header(partition_t *part)
216 erase_unit_header_t header;
217 loff_t offset, max_offset;
218 int ret;
219 part->header.FormattedSize = 0;
220 max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size;
221 /* Search first megabyte for a valid FTL header */
222 for (offset = 0;
223 (offset + sizeof(header)) < max_offset;
224 offset += part->mtd->erasesize ? : 0x2000) {
226 ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret,
227 (unsigned char *)&header);
229 if (ret)
230 return ret;
232 if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
235 if (offset == max_offset) {
236 printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
237 return -ENOENT;
239 if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
240 (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
241 (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
242 printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
243 return -1;
245 if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
246 printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
247 1 << header.EraseUnitSize,part->mtd->erasesize);
248 return -1;
250 part->header = header;
251 return 0;
254 static int build_maps(partition_t *part)
256 erase_unit_header_t header;
257 u_int16_t xvalid, xtrans, i;
258 u_int blocks, j;
259 int hdr_ok, ret = -1;
260 ssize_t retval;
261 loff_t offset;
263 /* Set up erase unit maps */
264 part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
265 part->header.NumTransferUnits;
266 part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
267 GFP_KERNEL);
268 if (!part->EUNInfo)
269 goto out;
270 for (i = 0; i < part->DataUnits; i++)
271 part->EUNInfo[i].Offset = 0xffffffff;
272 part->XferInfo =
273 kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
274 GFP_KERNEL);
275 if (!part->XferInfo)
276 goto out_EUNInfo;
278 xvalid = xtrans = 0;
279 for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
280 offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
281 << part->header.EraseUnitSize);
282 ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval,
283 (unsigned char *)&header);
285 if (ret)
286 goto out_XferInfo;
288 ret = -1;
289 /* Is this a transfer partition? */
290 hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
291 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
292 (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
293 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
294 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
295 le32_to_cpu(header.EraseCount);
296 xvalid++;
297 } else {
298 if (xtrans == part->header.NumTransferUnits) {
299 printk(KERN_NOTICE "ftl_cs: format error: too many "
300 "transfer units!\n");
301 goto out_XferInfo;
303 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
304 part->XferInfo[xtrans].state = XFER_PREPARED;
305 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
306 } else {
307 part->XferInfo[xtrans].state = XFER_UNKNOWN;
308 /* Pick anything reasonable for the erase count */
309 part->XferInfo[xtrans].EraseCount =
310 le32_to_cpu(part->header.EraseCount);
312 part->XferInfo[xtrans].Offset = offset;
313 xtrans++;
316 /* Check for format trouble */
317 header = part->header;
318 if ((xtrans != header.NumTransferUnits) ||
319 (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
320 printk(KERN_NOTICE "ftl_cs: format error: erase units "
321 "don't add up!\n");
322 goto out_XferInfo;
325 /* Set up virtual page map */
326 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
327 part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
328 if (!part->VirtualBlockMap)
329 goto out_XferInfo;
331 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
332 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
334 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
335 GFP_KERNEL);
336 if (!part->bam_cache)
337 goto out_VirtualBlockMap;
339 part->bam_index = 0xffff;
340 part->FreeTotal = 0;
342 for (i = 0; i < part->DataUnits; i++) {
343 part->EUNInfo[i].Free = 0;
344 part->EUNInfo[i].Deleted = 0;
345 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
347 ret = part->mtd->read(part->mtd, offset,
348 part->BlocksPerUnit * sizeof(u_int32_t), &retval,
349 (unsigned char *)part->bam_cache);
351 if (ret)
352 goto out_bam_cache;
354 for (j = 0; j < part->BlocksPerUnit; j++) {
355 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
356 part->EUNInfo[i].Free++;
357 part->FreeTotal++;
358 } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
359 (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
360 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
361 (i << header.EraseUnitSize) + (j << header.BlockSize);
362 else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
363 part->EUNInfo[i].Deleted++;
367 ret = 0;
368 goto out;
370 out_bam_cache:
371 kfree(part->bam_cache);
372 out_VirtualBlockMap:
373 vfree(part->VirtualBlockMap);
374 out_XferInfo:
375 kfree(part->XferInfo);
376 out_EUNInfo:
377 kfree(part->EUNInfo);
378 out:
379 return ret;
380 } /* build_maps */
382 /*======================================================================
384 Erase_xfer() schedules an asynchronous erase operation for a
385 transfer unit.
387 ======================================================================*/
389 static int erase_xfer(partition_t *part,
390 u_int16_t xfernum)
392 int ret;
393 struct xfer_info_t *xfer;
394 struct erase_info *erase;
396 xfer = &part->XferInfo[xfernum];
397 DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
398 xfer->state = XFER_ERASING;
400 /* Is there a free erase slot? Always in MTD. */
403 erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
404 if (!erase)
405 return -ENOMEM;
407 erase->callback = ftl_erase_callback;
408 erase->addr = xfer->Offset;
409 erase->len = 1 << part->header.EraseUnitSize;
410 erase->priv = (u_long)part;
412 ret = part->mtd->erase(part->mtd, erase);
414 if (!ret)
415 xfer->EraseCount++;
416 else
417 kfree(erase);
419 return ret;
420 } /* erase_xfer */
422 /*======================================================================
424 Prepare_xfer() takes a freshly erased transfer unit and gives
425 it an appropriate header.
427 ======================================================================*/
429 static void ftl_erase_callback(struct erase_info *erase)
431 partition_t *part;
432 struct xfer_info_t *xfer;
433 int i;
435 /* Look up the transfer unit */
436 part = (partition_t *)(erase->priv);
438 for (i = 0; i < part->header.NumTransferUnits; i++)
439 if (part->XferInfo[i].Offset == erase->addr) break;
441 if (i == part->header.NumTransferUnits) {
442 printk(KERN_NOTICE "ftl_cs: internal error: "
443 "erase lookup failed!\n");
444 return;
447 xfer = &part->XferInfo[i];
448 if (erase->state == MTD_ERASE_DONE)
449 xfer->state = XFER_ERASED;
450 else {
451 xfer->state = XFER_FAILED;
452 printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
453 erase->state);
456 kfree(erase);
458 } /* ftl_erase_callback */
460 static int prepare_xfer(partition_t *part, int i)
462 erase_unit_header_t header;
463 struct xfer_info_t *xfer;
464 int nbam, ret;
465 u_int32_t ctl;
466 ssize_t retlen;
467 loff_t offset;
469 xfer = &part->XferInfo[i];
470 xfer->state = XFER_FAILED;
472 DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
474 /* Write the transfer unit header */
475 header = part->header;
476 header.LogicalEUN = cpu_to_le16(0xffff);
477 header.EraseCount = cpu_to_le32(xfer->EraseCount);
479 ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
480 &retlen, (u_char *)&header);
482 if (ret) {
483 return ret;
486 /* Write the BAM stub */
487 nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
488 le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
490 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
491 ctl = cpu_to_le32(BLOCK_CONTROL);
493 for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
495 ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
496 &retlen, (u_char *)&ctl);
498 if (ret)
499 return ret;
501 xfer->state = XFER_PREPARED;
502 return 0;
504 } /* prepare_xfer */
506 /*======================================================================
508 Copy_erase_unit() takes a full erase block and a transfer unit,
509 copies everything to the transfer unit, then swaps the block
510 pointers.
512 All data blocks are copied to the corresponding blocks in the
513 target unit, so the virtual block map does not need to be
514 updated.
516 ======================================================================*/
518 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
519 u_int16_t xferunit)
521 u_char buf[SECTOR_SIZE];
522 struct eun_info_t *eun;
523 struct xfer_info_t *xfer;
524 u_int32_t src, dest, free, i;
525 u_int16_t unit;
526 int ret;
527 ssize_t retlen;
528 loff_t offset;
529 u_int16_t srcunitswap = cpu_to_le16(srcunit);
531 eun = &part->EUNInfo[srcunit];
532 xfer = &part->XferInfo[xferunit];
533 DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
534 eun->Offset, xfer->Offset);
537 /* Read current BAM */
538 if (part->bam_index != srcunit) {
540 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
542 ret = part->mtd->read(part->mtd, offset,
543 part->BlocksPerUnit * sizeof(u_int32_t),
544 &retlen, (u_char *) (part->bam_cache));
546 /* mark the cache bad, in case we get an error later */
547 part->bam_index = 0xffff;
549 if (ret) {
550 printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
551 return ret;
555 /* Write the LogicalEUN for the transfer unit */
556 xfer->state = XFER_UNKNOWN;
557 offset = xfer->Offset + 20; /* Bad! */
558 unit = cpu_to_le16(0x7fff);
560 ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
561 &retlen, (u_char *) &unit);
563 if (ret) {
564 printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
565 return ret;
568 /* Copy all data blocks from source unit to transfer unit */
569 src = eun->Offset; dest = xfer->Offset;
571 free = 0;
572 ret = 0;
573 for (i = 0; i < part->BlocksPerUnit; i++) {
574 switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
575 case BLOCK_CONTROL:
576 /* This gets updated later */
577 break;
578 case BLOCK_DATA:
579 case BLOCK_REPLACEMENT:
580 ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
581 &retlen, (u_char *) buf);
582 if (ret) {
583 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
584 return ret;
588 ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
589 &retlen, (u_char *) buf);
590 if (ret) {
591 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
592 return ret;
595 break;
596 default:
597 /* All other blocks must be free */
598 part->bam_cache[i] = cpu_to_le32(0xffffffff);
599 free++;
600 break;
602 src += SECTOR_SIZE;
603 dest += SECTOR_SIZE;
606 /* Write the BAM to the transfer unit */
607 ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
608 part->BlocksPerUnit * sizeof(int32_t), &retlen,
609 (u_char *)part->bam_cache);
610 if (ret) {
611 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
612 return ret;
616 /* All clear? Then update the LogicalEUN again */
617 ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
618 &retlen, (u_char *)&srcunitswap);
620 if (ret) {
621 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
622 return ret;
626 /* Update the maps and usage stats*/
627 i = xfer->EraseCount;
628 xfer->EraseCount = eun->EraseCount;
629 eun->EraseCount = i;
630 i = xfer->Offset;
631 xfer->Offset = eun->Offset;
632 eun->Offset = i;
633 part->FreeTotal -= eun->Free;
634 part->FreeTotal += free;
635 eun->Free = free;
636 eun->Deleted = 0;
638 /* Now, the cache should be valid for the new block */
639 part->bam_index = srcunit;
641 return 0;
642 } /* copy_erase_unit */
644 /*======================================================================
646 reclaim_block() picks a full erase unit and a transfer unit and
647 then calls copy_erase_unit() to copy one to the other. Then, it
648 schedules an erase on the expired block.
650 What's a good way to decide which transfer unit and which erase
651 unit to use? Beats me. My way is to always pick the transfer
652 unit with the fewest erases, and usually pick the data unit with
653 the most deleted blocks. But with a small probability, pick the
654 oldest data unit instead. This means that we generally postpone
655 the next reclaimation as long as possible, but shuffle static
656 stuff around a bit for wear leveling.
658 ======================================================================*/
660 static int reclaim_block(partition_t *part)
662 u_int16_t i, eun, xfer;
663 u_int32_t best;
664 int queued, ret;
666 DEBUG(0, "ftl_cs: reclaiming space...\n");
667 DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
668 /* Pick the least erased transfer unit */
669 best = 0xffffffff; xfer = 0xffff;
670 do {
671 queued = 0;
672 for (i = 0; i < part->header.NumTransferUnits; i++) {
673 int n=0;
674 if (part->XferInfo[i].state == XFER_UNKNOWN) {
675 DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
676 n=1;
677 erase_xfer(part, i);
679 if (part->XferInfo[i].state == XFER_ERASING) {
680 DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
681 n=1;
682 queued = 1;
684 else if (part->XferInfo[i].state == XFER_ERASED) {
685 DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
686 n=1;
687 prepare_xfer(part, i);
689 if (part->XferInfo[i].state == XFER_PREPARED) {
690 DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
691 n=1;
692 if (part->XferInfo[i].EraseCount <= best) {
693 best = part->XferInfo[i].EraseCount;
694 xfer = i;
697 if (!n)
698 DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
701 if (xfer == 0xffff) {
702 if (queued) {
703 DEBUG(1, "ftl_cs: waiting for transfer "
704 "unit to be prepared...\n");
705 if (part->mtd->sync)
706 part->mtd->sync(part->mtd);
707 } else {
708 static int ne = 0;
709 if (++ne < 5)
710 printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
711 "suitable transfer units!\n");
712 else
713 DEBUG(1, "ftl_cs: reclaim failed: no "
714 "suitable transfer units!\n");
716 return -EIO;
719 } while (xfer == 0xffff);
721 eun = 0;
722 if ((jiffies % shuffle_freq) == 0) {
723 DEBUG(1, "ftl_cs: recycling freshest block...\n");
724 best = 0xffffffff;
725 for (i = 0; i < part->DataUnits; i++)
726 if (part->EUNInfo[i].EraseCount <= best) {
727 best = part->EUNInfo[i].EraseCount;
728 eun = i;
730 } else {
731 best = 0;
732 for (i = 0; i < part->DataUnits; i++)
733 if (part->EUNInfo[i].Deleted >= best) {
734 best = part->EUNInfo[i].Deleted;
735 eun = i;
737 if (best == 0) {
738 static int ne = 0;
739 if (++ne < 5)
740 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
741 "no free blocks!\n");
742 else
743 DEBUG(1,"ftl_cs: reclaim failed: "
744 "no free blocks!\n");
746 return -EIO;
749 ret = copy_erase_unit(part, eun, xfer);
750 if (!ret)
751 erase_xfer(part, xfer);
752 else
753 printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
754 return ret;
755 } /* reclaim_block */
757 /*======================================================================
759 Find_free() searches for a free block. If necessary, it updates
760 the BAM cache for the erase unit containing the free block. It
761 returns the block index -- the erase unit is just the currently
762 cached unit. If there are no free blocks, it returns 0 -- this
763 is never a valid data block because it contains the header.
765 ======================================================================*/
767 #ifdef PSYCHO_DEBUG
768 static void dump_lists(partition_t *part)
770 int i;
771 printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
772 for (i = 0; i < part->DataUnits; i++)
773 printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
774 "%d deleted\n", i,
775 part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
776 part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
778 #endif
780 static u_int32_t find_free(partition_t *part)
782 u_int16_t stop, eun;
783 u_int32_t blk;
784 size_t retlen;
785 int ret;
787 /* Find an erase unit with some free space */
788 stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
789 eun = stop;
790 do {
791 if (part->EUNInfo[eun].Free != 0) break;
792 /* Wrap around at end of table */
793 if (++eun == part->DataUnits) eun = 0;
794 } while (eun != stop);
796 if (part->EUNInfo[eun].Free == 0)
797 return 0;
799 /* Is this unit's BAM cached? */
800 if (eun != part->bam_index) {
801 /* Invalidate cache */
802 part->bam_index = 0xffff;
804 ret = part->mtd->read(part->mtd,
805 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
806 part->BlocksPerUnit * sizeof(u_int32_t),
807 &retlen, (u_char *) (part->bam_cache));
809 if (ret) {
810 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
811 return 0;
813 part->bam_index = eun;
816 /* Find a free block */
817 for (blk = 0; blk < part->BlocksPerUnit; blk++)
818 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
819 if (blk == part->BlocksPerUnit) {
820 #ifdef PSYCHO_DEBUG
821 static int ne = 0;
822 if (++ne == 1)
823 dump_lists(part);
824 #endif
825 printk(KERN_NOTICE "ftl_cs: bad free list!\n");
826 return 0;
828 DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
829 return blk;
831 } /* find_free */
833 /*======================================================================
835 This gets a memory handle for the region corresponding to the
836 minor device number.
838 ======================================================================*/
840 static int ftl_open(struct inode *inode, struct file *file)
842 int minor = minor(inode->i_rdev);
843 partition_t *partition;
845 if (minor>>4 >= MAX_MTD_DEVICES)
846 return -ENODEV;
848 partition = myparts[minor>>4];
850 if (!partition)
851 return -ENODEV;
853 if (partition->state != FTL_FORMATTED)
854 return -ENXIO;
856 if (ftl_gendisk.part[minor].nr_sects == 0)
857 return -ENXIO;
859 if (!get_mtd_device(partition->mtd, -1))
860 return /* -E'SBUGGEREDOFF */ -ENXIO;
862 if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
863 put_mtd_device(partition->mtd);
864 return -EROFS;
867 DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
869 atomic_inc(&partition->open);
871 return 0;
874 /*====================================================================*/
876 static release_t ftl_close(struct inode *inode, struct file *file)
878 int minor = minor(inode->i_rdev);
879 partition_t *part = myparts[minor >> 4];
880 int i;
882 DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
884 /* Flush all writes */
885 invalidate_device(inode->i_rdev, 1);
887 /* Wait for any pending erase operations to complete */
888 if (part->mtd->sync)
889 part->mtd->sync(part->mtd);
891 for (i = 0; i < part->header.NumTransferUnits; i++) {
892 if (part->XferInfo[i].state == XFER_ERASED)
893 prepare_xfer(part, i);
896 atomic_dec(&part->open);
898 put_mtd_device(part->mtd);
899 release_return(0);
900 } /* ftl_close */
903 /*======================================================================
905 Read a series of sectors from an FTL partition.
907 ======================================================================*/
909 static int ftl_read(partition_t *part, caddr_t buffer,
910 u_long sector, u_long nblocks)
912 u_int32_t log_addr, bsize;
913 u_long i;
914 int ret;
915 size_t offset, retlen;
917 DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
918 part, sector, nblocks);
919 if (!(part->state & FTL_FORMATTED)) {
920 printk(KERN_NOTICE "ftl_cs: bad partition\n");
921 return -EIO;
923 bsize = 1 << part->header.EraseUnitSize;
925 for (i = 0; i < nblocks; i++) {
926 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
927 printk(KERN_NOTICE "ftl_cs: bad read offset\n");
928 return -EIO;
930 log_addr = part->VirtualBlockMap[sector+i];
931 if (log_addr == 0xffffffff)
932 memset(buffer, 0, SECTOR_SIZE);
933 else {
934 offset = (part->EUNInfo[log_addr / bsize].Offset
935 + (log_addr % bsize));
936 ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
937 &retlen, (u_char *) buffer);
939 if (ret) {
940 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
941 return ret;
944 buffer += SECTOR_SIZE;
946 return 0;
947 } /* ftl_read */
949 /*======================================================================
951 Write a series of sectors to an FTL partition
953 ======================================================================*/
955 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
956 u_int32_t virt_addr)
958 u_int32_t bsize, blk, le_virt_addr;
959 #ifdef PSYCHO_DEBUG
960 u_int32_t old_addr;
961 #endif
962 u_int16_t eun;
963 int ret;
964 size_t retlen, offset;
966 DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
967 part, log_addr, virt_addr);
968 bsize = 1 << part->header.EraseUnitSize;
969 eun = log_addr / bsize;
970 blk = (log_addr % bsize) / SECTOR_SIZE;
971 offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
972 le32_to_cpu(part->header.BAMOffset));
974 #ifdef PSYCHO_DEBUG
975 ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
976 &retlen, (u_char *)&old_addr);
977 if (ret) {
978 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
979 return ret;
981 old_addr = le32_to_cpu(old_addr);
983 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
984 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
985 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
986 static int ne = 0;
987 if (++ne < 5) {
988 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
989 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
990 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
992 return -EIO;
994 #endif
995 le_virt_addr = cpu_to_le32(virt_addr);
996 if (part->bam_index == eun) {
997 #ifdef PSYCHO_DEBUG
998 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
999 static int ne = 0;
1000 if (++ne < 5) {
1001 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
1002 "inconsistency!\n");
1003 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
1004 " = 0x%x\n",
1005 le32_to_cpu(part->bam_cache[blk]), old_addr);
1007 return -EIO;
1009 #endif
1010 part->bam_cache[blk] = le_virt_addr;
1012 ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
1013 &retlen, (u_char *)&le_virt_addr);
1015 if (ret) {
1016 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
1017 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
1018 log_addr, virt_addr);
1020 return ret;
1021 } /* set_bam_entry */
1023 static int ftl_write(partition_t *part, caddr_t buffer,
1024 u_long sector, u_long nblocks)
1026 u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
1027 u_long i;
1028 int ret;
1029 size_t retlen, offset;
1031 DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
1032 part, sector, nblocks);
1033 if (!(part->state & FTL_FORMATTED)) {
1034 printk(KERN_NOTICE "ftl_cs: bad partition\n");
1035 return -EIO;
1037 /* See if we need to reclaim space, before we start */
1038 while (part->FreeTotal < nblocks) {
1039 ret = reclaim_block(part);
1040 if (ret)
1041 return ret;
1044 bsize = 1 << part->header.EraseUnitSize;
1046 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
1047 for (i = 0; i < nblocks; i++) {
1048 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
1049 printk(KERN_NOTICE "ftl_cs: bad write offset\n");
1050 return -EIO;
1053 /* Grab a free block */
1054 blk = find_free(part);
1055 if (blk == 0) {
1056 static int ne = 0;
1057 if (++ne < 5)
1058 printk(KERN_NOTICE "ftl_cs: internal error: "
1059 "no free blocks!\n");
1060 return -ENOSPC;
1063 /* Tag the BAM entry, and write the new block */
1064 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
1065 part->EUNInfo[part->bam_index].Free--;
1066 part->FreeTotal--;
1067 if (set_bam_entry(part, log_addr, 0xfffffffe))
1068 return -EIO;
1069 part->EUNInfo[part->bam_index].Deleted++;
1070 offset = (part->EUNInfo[part->bam_index].Offset +
1071 blk * SECTOR_SIZE);
1072 ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen,
1073 buffer);
1075 if (ret) {
1076 printk(KERN_NOTICE "ftl_cs: block write failed!\n");
1077 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
1078 " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
1079 offset);
1080 return -EIO;
1083 /* Only delete the old entry when the new entry is ready */
1084 old_addr = part->VirtualBlockMap[sector+i];
1085 if (old_addr != 0xffffffff) {
1086 part->VirtualBlockMap[sector+i] = 0xffffffff;
1087 part->EUNInfo[old_addr/bsize].Deleted++;
1088 if (set_bam_entry(part, old_addr, 0))
1089 return -EIO;
1092 /* Finally, set up the new pointers */
1093 if (set_bam_entry(part, log_addr, virt_addr))
1094 return -EIO;
1095 part->VirtualBlockMap[sector+i] = log_addr;
1096 part->EUNInfo[part->bam_index].Deleted--;
1098 buffer += SECTOR_SIZE;
1099 virt_addr += SECTOR_SIZE;
1101 return 0;
1102 } /* ftl_write */
1104 /*======================================================================
1106 IOCTL calls for getting device parameters.
1108 ======================================================================*/
1110 static int ftl_ioctl(struct inode *inode, struct file *file,
1111 u_int cmd, u_long arg)
1113 struct hd_geometry *geo = (struct hd_geometry *)arg;
1114 int ret = 0, minor = minor(inode->i_rdev);
1115 partition_t *part= myparts[minor >> 4];
1116 u_long sect;
1118 if (!part)
1119 return -ENODEV; /* How? */
1121 switch (cmd) {
1122 case HDIO_GETGEO:
1123 ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
1124 if (ret) return ret;
1125 /* Sort of arbitrary: round size down to 4K boundary */
1126 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
1127 put_user(1, (char *)&geo->heads);
1128 put_user(8, (char *)&geo->sectors);
1129 put_user((sect>>3), (short *)&geo->cylinders);
1130 put_user(get_start_sect(inode->i_rdev), (u_long *)&geo->start);
1131 break;
1132 case BLKGETSIZE:
1133 ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
1134 break;
1135 case BLKGETSIZE64:
1136 ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
1137 break;
1138 case BLKRRPART:
1139 ret = ftl_reread_partitions(inode->i_rdev);
1140 break;
1141 case BLKROSET:
1142 case BLKROGET:
1143 case BLKFLSBUF:
1144 ret = blk_ioctl(inode->i_bdev, cmd, arg);
1145 break;
1146 default:
1147 ret = -EINVAL;
1150 return ret;
1151 } /* ftl_ioctl */
1153 /*======================================================================
1155 Handler for block device requests
1157 ======================================================================*/
1159 static int ftl_reread_partitions(kdev_t dev)
1161 int minor = minor(dev);
1162 partition_t *part = myparts[minor >> 4];
1163 int res;
1165 DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
1166 if ((atomic_read(&part->open) > 1)) {
1167 return -EBUSY;
1170 res = wipe_partitions(dev);
1171 if (res)
1172 goto leave;
1174 scan_header(part);
1176 register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
1177 &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
1179 return res;
1182 /*======================================================================
1184 Handler for block device requests
1186 ======================================================================*/
1188 static void do_ftl_request(request_arg_t)
1190 int ret, minor;
1191 partition_t *part;
1193 do {
1194 // sti();
1195 INIT_REQUEST;
1197 minor = minor(CURRENT->rq_dev);
1199 part = myparts[minor >> 4];
1200 if (part) {
1201 ret = 0;
1203 switch (CURRENT->cmd) {
1204 case READ:
1205 ret = ftl_read(part, CURRENT->buffer,
1206 CURRENT->sector+ftl_hd[minor].start_sect,
1207 CURRENT->current_nr_sectors);
1208 if (ret) printk("ftl_read returned %d\n", ret);
1209 break;
1211 case WRITE:
1212 ret = ftl_write(part, CURRENT->buffer,
1213 CURRENT->sector+ftl_hd[minor].start_sect,
1214 CURRENT->current_nr_sectors);
1215 if (ret) printk("ftl_write returned %d\n", ret);
1216 break;
1218 default:
1219 panic("ftl_cs: unknown block command!\n");
1222 } else {
1223 ret = 1;
1224 printk("NULL part in ftl_request\n");
1227 if (!ret) {
1228 CURRENT->sector += CURRENT->current_nr_sectors;
1231 end_request((ret == 0) ? 1 : 0);
1232 } while (1);
1233 } /* do_ftl_request */
1235 /*====================================================================*/
1237 void ftl_freepart(partition_t *part)
1239 if (part->VirtualBlockMap) {
1240 vfree(part->VirtualBlockMap);
1241 part->VirtualBlockMap = NULL;
1243 if (part->VirtualPageMap) {
1244 kfree(part->VirtualPageMap);
1245 part->VirtualPageMap = NULL;
1247 if (part->EUNInfo) {
1248 kfree(part->EUNInfo);
1249 part->EUNInfo = NULL;
1251 if (part->XferInfo) {
1252 kfree(part->XferInfo);
1253 part->XferInfo = NULL;
1255 if (part->bam_cache) {
1256 kfree(part->bam_cache);
1257 part->bam_cache = NULL;
1260 } /* ftl_freepart */
1262 static void ftl_notify_add(struct mtd_info *mtd)
1264 partition_t *partition;
1265 int device;
1267 for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
1270 if (device == MAX_MTD_DEVICES) {
1271 printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
1272 "Not scanning <%s>\n", mtd->name);
1273 return;
1276 partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
1278 if (!partition) {
1279 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1280 mtd->name);
1281 return;
1284 memset(partition, 0, sizeof(partition_t));
1286 partition->mtd = mtd;
1288 if ((scan_header(partition) == 0) &&
1289 (build_maps(partition) == 0)) {
1291 partition->state = FTL_FORMATTED;
1292 atomic_set(&partition->open, 0);
1293 myparts[device] = partition;
1294 ftl_reread_partitions(device << 4);
1295 #ifdef PCMCIA_DEBUG
1296 printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
1297 le32_to_cpu(partition->header.FormattedSize) >> 10);
1298 #endif
1299 } else
1300 kfree(partition);
1303 static void ftl_notify_remove(struct mtd_info *mtd)
1305 int i,j;
1307 /* Q: What happens if you try to remove a device which has
1308 * a currently-open FTL partition on it?
1310 * A: You don't. The ftl_open routine is responsible for
1311 * increasing the use count of the driver module which
1312 * it uses.
1315 /* That's the theory, anyway :) */
1317 for (i=0; i< MAX_MTD_DEVICES; i++)
1318 if (myparts[i] && myparts[i]->mtd == mtd) {
1320 if (myparts[i]->state == FTL_FORMATTED)
1321 ftl_freepart(myparts[i]);
1323 myparts[i]->state = 0;
1324 for (j=0; j<16; j++) {
1325 ftl_gendisk.part[j].nr_sects=0;
1326 ftl_gendisk.part[j].start_sect=0;
1328 kfree(myparts[i]);
1329 myparts[i] = NULL;
1333 int init_ftl(void)
1335 int i;
1337 memset(myparts, 0, sizeof(myparts));
1339 DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n");
1341 if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
1342 printk(KERN_NOTICE "ftl_cs: unable to grab major "
1343 "device number!\n");
1344 return -EAGAIN;
1347 for (i = 0; i < MAX_DEV*MAX_PART; i++) {
1348 ftl_hd[i].nr_sects = 0;
1349 ftl_hd[i].start_sect = 0;
1351 ftl_gendisk.major = FTL_MAJOR;
1352 blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
1353 add_gendisk(&ftl_gendisk);
1355 register_mtd_user(&ftl_notifier);
1357 return 0;
1360 static void __exit cleanup_ftl(void)
1362 unregister_mtd_user(&ftl_notifier);
1364 unregister_blkdev(FTL_MAJOR, "ftl");
1365 blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
1366 blk_clear(FTL_MAJOR);
1368 del_gendisk(&ftl_gendisk);
1371 module_init(init_ftl);
1372 module_exit(cleanup_ftl);
1375 MODULE_LICENSE("Dual MPL/GPL");
1376 MODULE_AUTHOR("David Hinds <dhinds@sonic.net>");
1377 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");