mtd: introduce mtd_write interface
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / mtd / ftl.c
CommitLineData
1da177e4 1/* This version ported to the Linux-MTD system by dwmw2@infradead.org
1da177e4
LT
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
a1452a37 29 are Copyright © 1999 David A. Hinds. All Rights Reserved.
1da177e4
LT
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,
631dd1a8 54 contact M-Systems directly. M-Systems since acquired by Sandisk.
97894cda 55
1da177e4
LT
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>
1da177e4
LT
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' */
80static int shuffle_freq = 50;
81module_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 */
110typedef struct partition_t {
111 struct mtd_blktrans_dev mbd;
3854be77
DW
112 uint32_t state;
113 uint32_t *VirtualBlockMap;
114 uint32_t *VirtualPageMap;
115 uint32_t FreeTotal;
1da177e4 116 struct eun_info_t {
3854be77
DW
117 uint32_t Offset;
118 uint32_t EraseCount;
119 uint32_t Free;
120 uint32_t Deleted;
1da177e4
LT
121 } *EUNInfo;
122 struct xfer_info_t {
3854be77
DW
123 uint32_t Offset;
124 uint32_t EraseCount;
125 uint16_t state;
1da177e4 126 } *XferInfo;
3854be77
DW
127 uint16_t bam_index;
128 uint32_t *bam_cache;
129 uint16_t DataUnits;
130 uint32_t BlocksPerUnit;
1da177e4 131 erase_unit_header_t header;
1da177e4
LT
132} partition_t;
133
1da177e4
LT
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
147static 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.
97894cda 155
1da177e4
LT
156======================================================================*/
157
158static 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
329ad399
AB
171 err = mtd_read(part->mbd.mtd, offset, sizeof(header), &ret,
172 (unsigned char *)&header);
97894cda
TG
173
174 if (err)
1da177e4
LT
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
199static int build_maps(partition_t *part)
200{
201 erase_unit_header_t header;
3854be77
DW
202 uint16_t xvalid, xtrans, i;
203 unsigned blocks, j;
1da177e4
LT
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);
329ad399
AB
227 ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval,
228 (unsigned char *)&header);
97894cda
TG
229
230 if (ret)
1da177e4
LT
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 }
97894cda 269
1da177e4
LT
270 /* Set up virtual page map */
271 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
3854be77 272 part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t));
1da177e4
LT
273 if (!part->VirtualBlockMap)
274 goto out_XferInfo;
275
3854be77 276 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
1da177e4
LT
277 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
278
3854be77 279 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t),
1da177e4
LT
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);
97894cda 291
329ad399
AB
292 ret = mtd_read(part->mbd.mtd, offset,
293 part->BlocksPerUnit * sizeof(uint32_t), &retval,
294 (unsigned char *)part->bam_cache);
97894cda
TG
295
296 if (ret)
1da177e4
LT
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 }
97894cda 311
1da177e4
LT
312 ret = 0;
313 goto out;
314
315out_bam_cache:
316 kfree(part->bam_cache);
317out_VirtualBlockMap:
318 vfree(part->VirtualBlockMap);
319out_XferInfo:
320 kfree(part->XferInfo);
321out_EUNInfo:
322 kfree(part->EUNInfo);
323out:
324 return ret;
325} /* build_maps */
326
327/*======================================================================
328
329 Erase_xfer() schedules an asynchronous erase operation for a
330 transfer unit.
97894cda 331
1da177e4
LT
332======================================================================*/
333
334static int erase_xfer(partition_t *part,
3854be77 335 uint16_t xfernum)
1da177e4
LT
336{
337 int ret;
338 struct xfer_info_t *xfer;
339 struct erase_info *erase;
340
341 xfer = &part->XferInfo[xfernum];
289c0522 342 pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
1da177e4
LT
343 xfer->state = XFER_ERASING;
344
345 /* Is there a free erase slot? Always in MTD. */
97894cda
TG
346
347
1da177e4 348 erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
97894cda 349 if (!erase)
1da177e4
LT
350 return -ENOMEM;
351
8ea2e06f 352 erase->mtd = part->mbd.mtd;
1da177e4
LT
353 erase->callback = ftl_erase_callback;
354 erase->addr = xfer->Offset;
355 erase->len = 1 << part->header.EraseUnitSize;
356 erase->priv = (u_long)part;
97894cda 357
7e1f0dc0 358 ret = mtd_erase(part->mbd.mtd, erase);
1da177e4
LT
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.
97894cda 372
1da177e4
LT
373======================================================================*/
374
375static void ftl_erase_callback(struct erase_info *erase)
376{
377 partition_t *part;
378 struct xfer_info_t *xfer;
379 int i;
97894cda 380
1da177e4
LT
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
406static 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;
3854be77 411 uint32_t ctl;
1da177e4
LT
412 ssize_t retlen;
413 loff_t offset;
414
415 xfer = &part->XferInfo[i];
416 xfer->state = XFER_FAILED;
97894cda 417
289c0522 418 pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
1da177e4
LT
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
eda95cbf
AB
425 ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen,
426 (u_char *)&header);
1da177e4
LT
427
428 if (ret) {
429 return ret;
430 }
431
432 /* Write the BAM stub */
3854be77 433 nbam = (part->BlocksPerUnit * sizeof(uint32_t) +
1da177e4
LT
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
3854be77 439 for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
1da177e4 440
eda95cbf
AB
441 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
442 (u_char *)&ctl);
1da177e4
LT
443
444 if (ret)
445 return ret;
446 }
447 xfer->state = XFER_PREPARED;
448 return 0;
97894cda 449
1da177e4
LT
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.
97894cda 461
1da177e4
LT
462======================================================================*/
463
3854be77
DW
464static int copy_erase_unit(partition_t *part, uint16_t srcunit,
465 uint16_t xferunit)
1da177e4
LT
466{
467 u_char buf[SECTOR_SIZE];
468 struct eun_info_t *eun;
469 struct xfer_info_t *xfer;
3854be77
DW
470 uint32_t src, dest, free, i;
471 uint16_t unit;
1da177e4
LT
472 int ret;
473 ssize_t retlen;
474 loff_t offset;
3854be77 475 uint16_t srcunitswap = cpu_to_le16(srcunit);
1da177e4
LT
476
477 eun = &part->EUNInfo[srcunit];
478 xfer = &part->XferInfo[xferunit];
289c0522 479 pr_debug("ftl_cs: copying block 0x%x to 0x%x\n",
1da177e4 480 eun->Offset, xfer->Offset);
97894cda
TG
481
482
1da177e4
LT
483 /* Read current BAM */
484 if (part->bam_index != srcunit) {
485
486 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
487
329ad399
AB
488 ret = mtd_read(part->mbd.mtd, offset,
489 part->BlocksPerUnit * sizeof(uint32_t), &retlen,
490 (u_char *)(part->bam_cache));
1da177e4
LT
491
492 /* mark the cache bad, in case we get an error later */
493 part->bam_index = 0xffff;
494
495 if (ret) {
97894cda 496 printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
1da177e4
LT
497 return ret;
498 }
499 }
97894cda 500
1da177e4
LT
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
eda95cbf
AB
506 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen,
507 (u_char *)&unit);
97894cda 508
1da177e4
LT
509 if (ret) {
510 printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
511 return ret;
512 }
97894cda 513
1da177e4
LT
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:
329ad399
AB
526 ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen,
527 (u_char *)buf);
1da177e4
LT
528 if (ret) {
529 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
530 return ret;
531 }
532
533
eda95cbf
AB
534 ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen,
535 (u_char *)buf);
1da177e4
LT
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 */
eda95cbf
AB
553 ret = mtd_write(part->mbd.mtd,
554 xfer->Offset + le32_to_cpu(part->header.BAMOffset),
555 part->BlocksPerUnit * sizeof(int32_t),
556 &retlen,
557 (u_char *)part->bam_cache);
1da177e4
LT
558 if (ret) {
559 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
560 return ret;
561 }
562
97894cda 563
1da177e4 564 /* All clear? Then update the LogicalEUN again */
eda95cbf
AB
565 ret = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
566 &retlen, (u_char *)&srcunitswap);
1da177e4
LT
567
568 if (ret) {
569 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
570 return ret;
97894cda
TG
571 }
572
573
1da177e4
LT
574 /* Update the maps and usage stats*/
575 i = xfer->EraseCount;
576 xfer->EraseCount = eun->EraseCount;
577 eun->EraseCount = i;
578 i = xfer->Offset;
579 xfer->Offset = eun->Offset;
580 eun->Offset = i;
581 part->FreeTotal -= eun->Free;
582 part->FreeTotal += free;
583 eun->Free = free;
584 eun->Deleted = 0;
97894cda 585
1da177e4
LT
586 /* Now, the cache should be valid for the new block */
587 part->bam_index = srcunit;
97894cda 588
1da177e4
LT
589 return 0;
590} /* copy_erase_unit */
591
592/*======================================================================
593
594 reclaim_block() picks a full erase unit and a transfer unit and
595 then calls copy_erase_unit() to copy one to the other. Then, it
596 schedules an erase on the expired block.
597
598 What's a good way to decide which transfer unit and which erase
599 unit to use? Beats me. My way is to always pick the transfer
600 unit with the fewest erases, and usually pick the data unit with
601 the most deleted blocks. But with a small probability, pick the
602 oldest data unit instead. This means that we generally postpone
92394b5c 603 the next reclamation as long as possible, but shuffle static
1da177e4 604 stuff around a bit for wear leveling.
97894cda 605
1da177e4
LT
606======================================================================*/
607
608static int reclaim_block(partition_t *part)
609{
3854be77
DW
610 uint16_t i, eun, xfer;
611 uint32_t best;
1da177e4
LT
612 int queued, ret;
613
289c0522
BN
614 pr_debug("ftl_cs: reclaiming space...\n");
615 pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits);
1da177e4
LT
616 /* Pick the least erased transfer unit */
617 best = 0xffffffff; xfer = 0xffff;
618 do {
619 queued = 0;
620 for (i = 0; i < part->header.NumTransferUnits; i++) {
621 int n=0;
622 if (part->XferInfo[i].state == XFER_UNKNOWN) {
289c0522 623 pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i);
1da177e4
LT
624 n=1;
625 erase_xfer(part, i);
626 }
627 if (part->XferInfo[i].state == XFER_ERASING) {
289c0522 628 pr_debug("XferInfo[%d].state == XFER_ERASING\n",i);
1da177e4
LT
629 n=1;
630 queued = 1;
631 }
632 else if (part->XferInfo[i].state == XFER_ERASED) {
289c0522 633 pr_debug("XferInfo[%d].state == XFER_ERASED\n",i);
1da177e4
LT
634 n=1;
635 prepare_xfer(part, i);
636 }
637 if (part->XferInfo[i].state == XFER_PREPARED) {
289c0522 638 pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i);
1da177e4
LT
639 n=1;
640 if (part->XferInfo[i].EraseCount <= best) {
641 best = part->XferInfo[i].EraseCount;
642 xfer = i;
643 }
644 }
645 if (!n)
289c0522 646 pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
1da177e4
LT
647
648 }
649 if (xfer == 0xffff) {
650 if (queued) {
289c0522 651 pr_debug("ftl_cs: waiting for transfer "
1da177e4
LT
652 "unit to be prepared...\n");
653 if (part->mbd.mtd->sync)
654 part->mbd.mtd->sync(part->mbd.mtd);
655 } else {
656 static int ne = 0;
657 if (++ne < 5)
658 printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
659 "suitable transfer units!\n");
660 else
289c0522 661 pr_debug("ftl_cs: reclaim failed: no "
1da177e4 662 "suitable transfer units!\n");
97894cda 663
1da177e4
LT
664 return -EIO;
665 }
666 }
667 } while (xfer == 0xffff);
668
669 eun = 0;
670 if ((jiffies % shuffle_freq) == 0) {
289c0522 671 pr_debug("ftl_cs: recycling freshest block...\n");
1da177e4
LT
672 best = 0xffffffff;
673 for (i = 0; i < part->DataUnits; i++)
674 if (part->EUNInfo[i].EraseCount <= best) {
675 best = part->EUNInfo[i].EraseCount;
676 eun = i;
677 }
678 } else {
679 best = 0;
680 for (i = 0; i < part->DataUnits; i++)
681 if (part->EUNInfo[i].Deleted >= best) {
682 best = part->EUNInfo[i].Deleted;
683 eun = i;
684 }
685 if (best == 0) {
686 static int ne = 0;
687 if (++ne < 5)
688 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
689 "no free blocks!\n");
690 else
289c0522 691 pr_debug("ftl_cs: reclaim failed: "
1da177e4
LT
692 "no free blocks!\n");
693
694 return -EIO;
695 }
696 }
697 ret = copy_erase_unit(part, eun, xfer);
698 if (!ret)
699 erase_xfer(part, xfer);
700 else
701 printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
702 return ret;
703} /* reclaim_block */
704
705/*======================================================================
706
707 Find_free() searches for a free block. If necessary, it updates
708 the BAM cache for the erase unit containing the free block. It
709 returns the block index -- the erase unit is just the currently
710 cached unit. If there are no free blocks, it returns 0 -- this
711 is never a valid data block because it contains the header.
97894cda 712
1da177e4
LT
713======================================================================*/
714
715#ifdef PSYCHO_DEBUG
716static void dump_lists(partition_t *part)
717{
718 int i;
719 printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
720 for (i = 0; i < part->DataUnits; i++)
721 printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
722 "%d deleted\n", i,
723 part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
724 part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
725}
726#endif
727
3854be77 728static uint32_t find_free(partition_t *part)
1da177e4 729{
3854be77
DW
730 uint16_t stop, eun;
731 uint32_t blk;
1da177e4
LT
732 size_t retlen;
733 int ret;
97894cda 734
1da177e4
LT
735 /* Find an erase unit with some free space */
736 stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
737 eun = stop;
738 do {
739 if (part->EUNInfo[eun].Free != 0) break;
740 /* Wrap around at end of table */
741 if (++eun == part->DataUnits) eun = 0;
742 } while (eun != stop);
743
744 if (part->EUNInfo[eun].Free == 0)
745 return 0;
97894cda 746
1da177e4
LT
747 /* Is this unit's BAM cached? */
748 if (eun != part->bam_index) {
749 /* Invalidate cache */
750 part->bam_index = 0xffff;
751
329ad399
AB
752 ret = mtd_read(part->mbd.mtd,
753 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
754 part->BlocksPerUnit * sizeof(uint32_t),
755 &retlen,
756 (u_char *)(part->bam_cache));
97894cda 757
1da177e4
LT
758 if (ret) {
759 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
760 return 0;
761 }
762 part->bam_index = eun;
763 }
764
765 /* Find a free block */
766 for (blk = 0; blk < part->BlocksPerUnit; blk++)
767 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
768 if (blk == part->BlocksPerUnit) {
769#ifdef PSYCHO_DEBUG
770 static int ne = 0;
771 if (++ne == 1)
772 dump_lists(part);
773#endif
774 printk(KERN_NOTICE "ftl_cs: bad free list!\n");
775 return 0;
776 }
289c0522 777 pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun);
1da177e4 778 return blk;
97894cda 779
1da177e4
LT
780} /* find_free */
781
782
783/*======================================================================
784
785 Read a series of sectors from an FTL partition.
97894cda 786
1da177e4
LT
787======================================================================*/
788
789static int ftl_read(partition_t *part, caddr_t buffer,
790 u_long sector, u_long nblocks)
791{
3854be77 792 uint32_t log_addr, bsize;
1da177e4
LT
793 u_long i;
794 int ret;
795 size_t offset, retlen;
97894cda 796
289c0522 797 pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
1da177e4
LT
798 part, sector, nblocks);
799 if (!(part->state & FTL_FORMATTED)) {
800 printk(KERN_NOTICE "ftl_cs: bad partition\n");
801 return -EIO;
802 }
803 bsize = 1 << part->header.EraseUnitSize;
804
805 for (i = 0; i < nblocks; i++) {
806 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
807 printk(KERN_NOTICE "ftl_cs: bad read offset\n");
808 return -EIO;
809 }
810 log_addr = part->VirtualBlockMap[sector+i];
811 if (log_addr == 0xffffffff)
812 memset(buffer, 0, SECTOR_SIZE);
813 else {
814 offset = (part->EUNInfo[log_addr / bsize].Offset
815 + (log_addr % bsize));
329ad399
AB
816 ret = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
817 (u_char *)buffer);
1da177e4
LT
818
819 if (ret) {
820 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
821 return ret;
822 }
823 }
824 buffer += SECTOR_SIZE;
825 }
826 return 0;
827} /* ftl_read */
828
829/*======================================================================
830
831 Write a series of sectors to an FTL partition
97894cda 832
1da177e4
LT
833======================================================================*/
834
3854be77
DW
835static int set_bam_entry(partition_t *part, uint32_t log_addr,
836 uint32_t virt_addr)
1da177e4 837{
3854be77 838 uint32_t bsize, blk, le_virt_addr;
1da177e4 839#ifdef PSYCHO_DEBUG
3854be77 840 uint32_t old_addr;
1da177e4 841#endif
3854be77 842 uint16_t eun;
1da177e4
LT
843 int ret;
844 size_t retlen, offset;
845
289c0522 846 pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
1da177e4
LT
847 part, log_addr, virt_addr);
848 bsize = 1 << part->header.EraseUnitSize;
849 eun = log_addr / bsize;
850 blk = (log_addr % bsize) / SECTOR_SIZE;
3854be77 851 offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
1da177e4 852 le32_to_cpu(part->header.BAMOffset));
97894cda 853
1da177e4 854#ifdef PSYCHO_DEBUG
329ad399
AB
855 ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
856 (u_char *)&old_addr);
1da177e4
LT
857 if (ret) {
858 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
859 return ret;
860 }
861 old_addr = le32_to_cpu(old_addr);
862
863 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
864 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
865 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
866 static int ne = 0;
867 if (++ne < 5) {
868 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
869 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
870 ", new = 0x%x\n", log_addr, old_addr, virt_addr);
871 }
872 return -EIO;
873 }
874#endif
875 le_virt_addr = cpu_to_le32(virt_addr);
876 if (part->bam_index == eun) {
877#ifdef PSYCHO_DEBUG
878 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
879 static int ne = 0;
880 if (++ne < 5) {
881 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
882 "inconsistency!\n");
883 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
884 " = 0x%x\n",
885 le32_to_cpu(part->bam_cache[blk]), old_addr);
886 }
887 return -EIO;
888 }
889#endif
890 part->bam_cache[blk] = le_virt_addr;
891 }
eda95cbf
AB
892 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
893 (u_char *)&le_virt_addr);
1da177e4
LT
894
895 if (ret) {
896 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
897 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
898 log_addr, virt_addr);
899 }
900 return ret;
901} /* set_bam_entry */
902
903static int ftl_write(partition_t *part, caddr_t buffer,
904 u_long sector, u_long nblocks)
905{
3854be77 906 uint32_t bsize, log_addr, virt_addr, old_addr, blk;
1da177e4
LT
907 u_long i;
908 int ret;
909 size_t retlen, offset;
910
289c0522 911 pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
1da177e4
LT
912 part, sector, nblocks);
913 if (!(part->state & FTL_FORMATTED)) {
914 printk(KERN_NOTICE "ftl_cs: bad partition\n");
915 return -EIO;
916 }
917 /* See if we need to reclaim space, before we start */
918 while (part->FreeTotal < nblocks) {
919 ret = reclaim_block(part);
920 if (ret)
921 return ret;
922 }
97894cda 923
1da177e4
LT
924 bsize = 1 << part->header.EraseUnitSize;
925
926 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
927 for (i = 0; i < nblocks; i++) {
928 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
929 printk(KERN_NOTICE "ftl_cs: bad write offset\n");
930 return -EIO;
931 }
932
933 /* Grab a free block */
934 blk = find_free(part);
935 if (blk == 0) {
936 static int ne = 0;
937 if (++ne < 5)
938 printk(KERN_NOTICE "ftl_cs: internal error: "
939 "no free blocks!\n");
940 return -ENOSPC;
941 }
942
943 /* Tag the BAM entry, and write the new block */
944 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
945 part->EUNInfo[part->bam_index].Free--;
946 part->FreeTotal--;
97894cda 947 if (set_bam_entry(part, log_addr, 0xfffffffe))
1da177e4
LT
948 return -EIO;
949 part->EUNInfo[part->bam_index].Deleted++;
950 offset = (part->EUNInfo[part->bam_index].Offset +
951 blk * SECTOR_SIZE);
eda95cbf 952 ret = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer);
1da177e4
LT
953
954 if (ret) {
955 printk(KERN_NOTICE "ftl_cs: block write failed!\n");
956 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
957 " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
958 offset);
959 return -EIO;
960 }
97894cda 961
1da177e4
LT
962 /* Only delete the old entry when the new entry is ready */
963 old_addr = part->VirtualBlockMap[sector+i];
964 if (old_addr != 0xffffffff) {
965 part->VirtualBlockMap[sector+i] = 0xffffffff;
966 part->EUNInfo[old_addr/bsize].Deleted++;
967 if (set_bam_entry(part, old_addr, 0))
968 return -EIO;
969 }
970
971 /* Finally, set up the new pointers */
972 if (set_bam_entry(part, log_addr, virt_addr))
973 return -EIO;
974 part->VirtualBlockMap[sector+i] = log_addr;
975 part->EUNInfo[part->bam_index].Deleted--;
97894cda 976
1da177e4
LT
977 buffer += SECTOR_SIZE;
978 virt_addr += SECTOR_SIZE;
979 }
980 return 0;
981} /* ftl_write */
982
983static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
984{
985 partition_t *part = (void *)dev;
986 u_long sect;
987
988 /* Sort of arbitrary: round size down to 4KiB boundary */
989 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
990
991 geo->heads = 1;
992 geo->sectors = 8;
993 geo->cylinders = sect >> 3;
994
995 return 0;
996}
997
998static int ftl_readsect(struct mtd_blktrans_dev *dev,
999 unsigned long block, char *buf)
1000{
1001 return ftl_read((void *)dev, buf, block, 1);
1002}
1003
1004static int ftl_writesect(struct mtd_blktrans_dev *dev,
1005 unsigned long block, char *buf)
1006{
1007 return ftl_write((void *)dev, buf, block, 1);
1008}
1009
fdc53971
DW
1010static int ftl_discardsect(struct mtd_blktrans_dev *dev,
1011 unsigned long sector, unsigned nr_sects)
1012{
1013 partition_t *part = (void *)dev;
1014 uint32_t bsize = 1 << part->header.EraseUnitSize;
1015
289c0522 1016 pr_debug("FTL erase sector %ld for %d sectors\n",
fdc53971
DW
1017 sector, nr_sects);
1018
1019 while (nr_sects) {
1020 uint32_t old_addr = part->VirtualBlockMap[sector];
1021 if (old_addr != 0xffffffff) {
1022 part->VirtualBlockMap[sector] = 0xffffffff;
1023 part->EUNInfo[old_addr/bsize].Deleted++;
1024 if (set_bam_entry(part, old_addr, 0))
1025 return -EIO;
1026 }
1027 nr_sects--;
1028 sector++;
1029 }
1030
1031 return 0;
1032}
1da177e4
LT
1033/*====================================================================*/
1034
5ce45d50 1035static void ftl_freepart(partition_t *part)
1da177e4 1036{
1da177e4
LT
1037 vfree(part->VirtualBlockMap);
1038 part->VirtualBlockMap = NULL;
1da177e4
LT
1039 kfree(part->VirtualPageMap);
1040 part->VirtualPageMap = NULL;
1da177e4
LT
1041 kfree(part->EUNInfo);
1042 part->EUNInfo = NULL;
1da177e4
LT
1043 kfree(part->XferInfo);
1044 part->XferInfo = NULL;
1da177e4
LT
1045 kfree(part->bam_cache);
1046 part->bam_cache = NULL;
1da177e4
LT
1047} /* ftl_freepart */
1048
1049static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1050{
1051 partition_t *partition;
1052
95b93a0c 1053 partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
97894cda 1054
1da177e4
LT
1055 if (!partition) {
1056 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1057 mtd->name);
1058 return;
97894cda 1059 }
1da177e4 1060
1da177e4
LT
1061 partition->mbd.mtd = mtd;
1062
97894cda 1063 if ((scan_header(partition) == 0) &&
1da177e4 1064 (build_maps(partition) == 0)) {
97894cda 1065
1da177e4
LT
1066 partition->state = FTL_FORMATTED;
1067#ifdef PCMCIA_DEBUG
1068 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1069 le32_to_cpu(partition->header.FormattedSize) >> 10);
1070#endif
1071 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
19187672 1072
1da177e4
LT
1073 partition->mbd.tr = tr;
1074 partition->mbd.devnum = -1;
1075 if (!add_mtd_blktrans_dev((void *)partition))
1076 return;
1077 }
1078
1079 ftl_freepart(partition);
1080 kfree(partition);
1081}
1082
1083static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1084{
1085 del_mtd_blktrans_dev(dev);
1086 ftl_freepart((partition_t *)dev);
1da177e4
LT
1087}
1088
5ce45d50 1089static struct mtd_blktrans_ops ftl_tr = {
1da177e4
LT
1090 .name = "ftl",
1091 .major = FTL_MAJOR,
1092 .part_bits = PART_BITS,
19187672 1093 .blksize = SECTOR_SIZE,
1da177e4
LT
1094 .readsect = ftl_readsect,
1095 .writesect = ftl_writesect,
fdc53971 1096 .discard = ftl_discardsect,
1da177e4
LT
1097 .getgeo = ftl_getgeo,
1098 .add_mtd = ftl_add_mtd,
1099 .remove_dev = ftl_remove_dev,
1100 .owner = THIS_MODULE,
1101};
1102
627df23c 1103static int __init init_ftl(void)
1da177e4 1104{
1da177e4
LT
1105 return register_mtd_blktrans(&ftl_tr);
1106}
1107
1108static void __exit cleanup_ftl(void)
1109{
1110 deregister_mtd_blktrans(&ftl_tr);
1111}
1112
1113module_init(init_ftl);
1114module_exit(cleanup_ftl);
1115
1116
1117MODULE_LICENSE("Dual MPL/GPL");
1118MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1119MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");