2
* inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
4
* Copyright Ā© 2002, Greg Ungerer (gerg@snapgear.com)
6
* Based heavily on the nftlcore.c code which is:
7
* Copyright Ā© 1999 Machine Vision Holdings, Inc.
8
* Copyright Ā© 1999 David Woodhouse <dwmw2@infradead.org>
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
#include <linux/kernel.h>
26
#include <linux/module.h>
27
#include <linux/delay.h>
28
#include <linux/slab.h>
29
#include <linux/sched.h>
30
#include <linux/init.h>
31
#include <linux/kmod.h>
32
#include <linux/hdreg.h>
33
#include <linux/mtd/mtd.h>
34
#include <linux/mtd/nftl.h>
35
#include <linux/mtd/inftl.h>
36
#include <linux/mtd/nand.h>
37
#include <asm/uaccess.h>
38
#include <asm/errno.h>
42
* Maximum number of loops while examining next block, to have a
43
* chance to detect consistency problems (they should never happen
44
* because of the checks done in the mounting.
46
#define MAX_LOOPS 10000
48
static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
50
struct INFTLrecord *inftl;
53
if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
55
/* OK, this is moderately ugly. But probably safe. Alternatives? */
56
if (memcmp(mtd->name, "DiskOnChip", 10))
59
if (!mtd->block_isbad) {
61
"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
62
"Please use the new diskonchip driver under the NAND subsystem.\n");
66
pr_debug("INFTL: add_mtd for %s\n", mtd->name);
68
inftl = kzalloc(sizeof(*inftl), GFP_KERNEL);
74
inftl->mbd.devnum = -1;
78
if (INFTL_mount(inftl) < 0) {
79
printk(KERN_WARNING "INFTL: could not mount device\n");
84
/* OK, it's a new one. Set up all the data structures. */
86
/* Calculate geometry */
87
inftl->cylinders = 1024;
90
temp = inftl->cylinders * inftl->heads;
91
inftl->sectors = inftl->mbd.size / temp;
92
if (inftl->mbd.size % temp) {
94
temp = inftl->cylinders * inftl->sectors;
95
inftl->heads = inftl->mbd.size / temp;
97
if (inftl->mbd.size % temp) {
99
temp = inftl->heads * inftl->sectors;
100
inftl->cylinders = inftl->mbd.size / temp;
104
if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
107
mbd.size == heads * cylinders * sectors
109
printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
110
"match size of 0x%lx.\n", inftl->mbd.size);
111
printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
112
"(== 0x%lx sects)\n",
113
inftl->cylinders, inftl->heads , inftl->sectors,
114
(long)inftl->cylinders * (long)inftl->heads *
115
(long)inftl->sectors );
118
if (add_mtd_blktrans_dev(&inftl->mbd)) {
119
kfree(inftl->PUtable);
120
kfree(inftl->VUtable);
125
printk(KERN_INFO "INFTL: Found new inftl%c\n", inftl->mbd.devnum + 'a');
130
static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
132
struct INFTLrecord *inftl = (void *)dev;
134
pr_debug("INFTL: remove_dev (i=%d)\n", dev->devnum);
136
del_mtd_blktrans_dev(dev);
138
kfree(inftl->PUtable);
139
kfree(inftl->VUtable);
143
* Actual INFTL access routines.
147
* Read oob data from flash
149
int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
150
size_t *retlen, uint8_t *buf)
152
struct mtd_oob_ops ops;
155
ops.mode = MTD_OPS_PLACE_OOB;
156
ops.ooboffs = offs & (mtd->writesize - 1);
161
res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
162
*retlen = ops.oobretlen;
167
* Write oob data to flash
169
int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
170
size_t *retlen, uint8_t *buf)
172
struct mtd_oob_ops ops;
175
ops.mode = MTD_OPS_PLACE_OOB;
176
ops.ooboffs = offs & (mtd->writesize - 1);
181
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
182
*retlen = ops.oobretlen;
187
* Write data and oob to flash
189
static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
190
size_t *retlen, uint8_t *buf, uint8_t *oob)
192
struct mtd_oob_ops ops;
195
ops.mode = MTD_OPS_PLACE_OOB;
197
ops.ooblen = mtd->oobsize;
202
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
203
*retlen = ops.retlen;
208
* INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
209
* This function is used when the give Virtual Unit Chain.
211
static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
213
u16 pot = inftl->LastFreeEUN;
214
int silly = inftl->nb_blocks;
216
pr_debug("INFTL: INFTL_findfreeblock(inftl=%p,desperate=%d)\n",
220
* Normally, we force a fold to happen before we run out of free
223
if (!desperate && inftl->numfreeEUNs < 2) {
224
pr_debug("INFTL: there are too few free EUNs (%d)\n",
229
/* Scan for a free block */
231
if (inftl->PUtable[pot] == BLOCK_FREE) {
232
inftl->LastFreeEUN = pot;
236
if (++pot > inftl->lastEUN)
240
printk(KERN_WARNING "INFTL: no free blocks found! "
241
"EUN range = %d - %d\n", 0, inftl->LastFreeEUN);
244
} while (pot != inftl->LastFreeEUN);
249
static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock)
251
u16 BlockMap[MAX_SECTORS_PER_UNIT];
252
unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
253
unsigned int thisEUN, prevEUN, status;
254
struct mtd_info *mtd = inftl->mbd.mtd;
256
unsigned int targetEUN;
257
struct inftl_oob oob;
260
pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n",
261
inftl, thisVUC, pendingblock);
263
memset(BlockMap, 0xff, sizeof(BlockMap));
264
memset(BlockDeleted, 0, sizeof(BlockDeleted));
266
thisEUN = targetEUN = inftl->VUtable[thisVUC];
268
if (thisEUN == BLOCK_NIL) {
269
printk(KERN_WARNING "INFTL: trying to fold non-existent "
270
"Virtual Unit Chain %d!\n", thisVUC);
275
* Scan to find the Erase Unit which holds the actual data for each
276
* 512-byte block within the Chain.
279
while (thisEUN < inftl->nb_blocks) {
280
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
281
if ((BlockMap[block] != BLOCK_NIL) ||
285
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
286
+ (block * SECTORSIZE), 16, &retlen,
288
status = SECTOR_IGNORE;
290
status = oob.b.Status | oob.b.Status1;
297
BlockMap[block] = thisEUN;
300
BlockDeleted[block] = 1;
303
printk(KERN_WARNING "INFTL: unknown status "
304
"for block %d in EUN %d: %x\n",
305
block, thisEUN, status);
311
printk(KERN_WARNING "INFTL: infinite loop in Virtual "
312
"Unit Chain 0x%x\n", thisVUC);
316
thisEUN = inftl->PUtable[thisEUN];
320
* OK. We now know the location of every block in the Virtual Unit
321
* Chain, and the Erase Unit into which we are supposed to be copying.
324
pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN);
326
for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {
327
unsigned char movebuf[SECTORSIZE];
331
* If it's in the target EUN already, or if it's pending write,
334
if (BlockMap[block] == targetEUN || (pendingblock ==
335
(thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) {
340
* Copy only in non free block (free blocks can only
341
* happen in case of media errors or deleted blocks).
343
if (BlockMap[block] == BLOCK_NIL)
346
ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
347
(block * SECTORSIZE), SECTORSIZE, &retlen,
349
if (ret < 0 && !mtd_is_bitflip(ret)) {
351
(inftl->EraseSize * BlockMap[block]) +
352
(block * SECTORSIZE), SECTORSIZE,
355
pr_debug("INFTL: error went away on retry?\n");
357
memset(&oob, 0xff, sizeof(struct inftl_oob));
358
oob.b.Status = oob.b.Status1 = SECTOR_USED;
360
inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
361
(block * SECTORSIZE), SECTORSIZE, &retlen,
362
movebuf, (char *)&oob);
366
* Newest unit in chain now contains data from _all_ older units.
367
* So go through and erase each unit in chain, oldest first. (This
368
* is important, by doing oldest first if we crash/reboot then it
369
* it is relatively simple to clean up the mess).
371
pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC);
374
/* Find oldest unit in chain. */
375
thisEUN = inftl->VUtable[thisVUC];
377
while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
379
thisEUN = inftl->PUtable[thisEUN];
382
/* Check if we are all done */
383
if (thisEUN == targetEUN)
386
/* Unlink the last block from the chain. */
387
inftl->PUtable[prevEUN] = BLOCK_NIL;
389
/* Now try to erase it. */
390
if (INFTL_formatblock(inftl, thisEUN) < 0) {
392
* Could not erase : mark block as reserved.
394
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
396
/* Correctly erased : mark it as free */
397
inftl->PUtable[thisEUN] = BLOCK_FREE;
398
inftl->numfreeEUNs++;
405
static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
408
* This is the part that needs some cleverness applied.
409
* For now, I'm doing the minimum applicable to actually
410
* get the thing to work.
411
* Wear-levelling and other clever stuff needs to be implemented
412
* and we also need to do some assessment of the results when
413
* the system loses power half-way through the routine.
415
u16 LongestChain = 0;
416
u16 ChainLength = 0, thislen;
419
pr_debug("INFTL: INFTL_makefreeblock(inftl=%p,"
420
"pending=%d)\n", inftl, pendingblock);
422
for (chain = 0; chain < inftl->nb_blocks; chain++) {
423
EUN = inftl->VUtable[chain];
426
while (EUN <= inftl->lastEUN) {
428
EUN = inftl->PUtable[EUN];
429
if (thislen > 0xff00) {
430
printk(KERN_WARNING "INFTL: endless loop in "
431
"Virtual Chain %d: Unit %x\n",
434
* Actually, don't return failure.
435
* Just ignore this chain and get on with it.
442
if (thislen > ChainLength) {
443
ChainLength = thislen;
444
LongestChain = chain;
448
if (ChainLength < 2) {
449
printk(KERN_WARNING "INFTL: no Virtual Unit Chains available "
450
"for folding. Failing request\n");
454
return INFTL_foldchain(inftl, LongestChain, pendingblock);
457
static int nrbits(unsigned int val, int bitcount)
461
for (i = 0; (i < bitcount); i++)
462
total += (((0x1 << i) & val) ? 1 : 0);
467
* INFTL_findwriteunit: Return the unit number into which we can write
468
* for this block. Make it available if it isn't already.
470
static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
472
unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE);
473
unsigned int thisEUN, writeEUN, prev_block, status;
474
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1);
475
struct mtd_info *mtd = inftl->mbd.mtd;
476
struct inftl_oob oob;
477
struct inftl_bci bci;
478
unsigned char anac, nacs, parity;
480
int silly, silly2 = 3;
482
pr_debug("INFTL: INFTL_findwriteunit(inftl=%p,block=%d)\n",
487
* Scan the media to find a unit in the VUC which has
488
* a free space for the block in question.
490
writeEUN = BLOCK_NIL;
491
thisEUN = inftl->VUtable[thisVUC];
494
while (thisEUN <= inftl->lastEUN) {
495
inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
496
blockofs, 8, &retlen, (char *)&bci);
498
status = bci.Status | bci.Status1;
499
pr_debug("INFTL: status of block %d in EUN %d is %x\n",
500
block , writeEUN, status);
508
/* Can't go any further */
514
* Invalid block. Don't use it any more.
521
printk(KERN_WARNING "INFTL: infinite loop in "
522
"Virtual Unit Chain 0x%x\n", thisVUC);
526
/* Skip to next block in chain */
527
thisEUN = inftl->PUtable[thisEUN];
531
if (writeEUN != BLOCK_NIL)
536
* OK. We didn't find one in the existing chain, or there
537
* is no existing chain. Allocate a new one.
539
writeEUN = INFTL_findfreeblock(inftl, 0);
541
if (writeEUN == BLOCK_NIL) {
543
* That didn't work - there were no free blocks just
544
* waiting to be picked up. We're going to have to fold
545
* a chain to make room.
547
thisEUN = INFTL_makefreeblock(inftl, block);
550
* Hopefully we free something, lets try again.
551
* This time we are desperate...
553
pr_debug("INFTL: using desperate==1 to find free EUN "
554
"to accommodate write to VUC %d\n",
556
writeEUN = INFTL_findfreeblock(inftl, 1);
557
if (writeEUN == BLOCK_NIL) {
559
* Ouch. This should never happen - we should
560
* always be able to make some room somehow.
561
* If we get here, we've allocated more storage
562
* space than actual media, or our makefreeblock
563
* routine is missing something.
565
printk(KERN_WARNING "INFTL: cannot make free "
568
INFTL_dumptables(inftl);
569
INFTL_dumpVUchains(inftl);
576
* Insert new block into virtual chain. Firstly update the
577
* block headers in flash...
581
thisEUN = inftl->VUtable[thisVUC];
582
if (thisEUN != BLOCK_NIL) {
583
inftl_read_oob(mtd, thisEUN * inftl->EraseSize
584
+ 8, 8, &retlen, (char *)&oob.u);
585
anac = oob.u.a.ANAC + 1;
586
nacs = oob.u.a.NACs + 1;
589
prev_block = inftl->VUtable[thisVUC];
590
if (prev_block < inftl->nb_blocks)
591
prev_block -= inftl->firstEUN;
593
parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0;
594
parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
595
parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
596
parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
598
oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
599
oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
602
oob.u.a.parityPerField = parity;
603
oob.u.a.discarded = 0xaa;
605
inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8,
606
&retlen, (char *)&oob.u);
608
/* Also back up header... */
609
oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);
610
oob.u.b.prevUnitNo = cpu_to_le16(prev_block);
613
oob.u.b.parityPerField = parity;
614
oob.u.b.discarded = 0xaa;
616
inftl_write_oob(mtd, writeEUN * inftl->EraseSize +
617
SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
619
inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
620
inftl->VUtable[thisVUC] = writeEUN;
622
inftl->numfreeEUNs--;
627
printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
628
"Unit Chain 0x%x\n", thisVUC);
633
* Given a Virtual Unit Chain, see if it can be deleted, and if so do it.
635
static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
637
struct mtd_info *mtd = inftl->mbd.mtd;
638
unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];
639
unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
640
unsigned int thisEUN, status;
642
struct inftl_bci bci;
645
pr_debug("INFTL: INFTL_trydeletechain(inftl=%p,"
646
"thisVUC=%d)\n", inftl, thisVUC);
648
memset(BlockUsed, 0, sizeof(BlockUsed));
649
memset(BlockDeleted, 0, sizeof(BlockDeleted));
651
thisEUN = inftl->VUtable[thisVUC];
652
if (thisEUN == BLOCK_NIL) {
653
printk(KERN_WARNING "INFTL: trying to delete non-existent "
654
"Virtual Unit Chain %d!\n", thisVUC);
659
* Scan through the Erase Units to determine whether any data is in
660
* each of the 512-byte blocks within the Chain.
663
while (thisEUN < inftl->nb_blocks) {
664
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) {
665
if (BlockUsed[block] || BlockDeleted[block])
668
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
669
+ (block * SECTORSIZE), 8 , &retlen,
671
status = SECTOR_IGNORE;
673
status = bci.Status | bci.Status1;
680
BlockUsed[block] = 1;
683
BlockDeleted[block] = 1;
686
printk(KERN_WARNING "INFTL: unknown status "
687
"for block %d in EUN %d: 0x%x\n",
688
block, thisEUN, status);
693
printk(KERN_WARNING "INFTL: infinite loop in Virtual "
694
"Unit Chain 0x%x\n", thisVUC);
698
thisEUN = inftl->PUtable[thisEUN];
701
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++)
702
if (BlockUsed[block])
706
* For each block in the chain free it and make it available
707
* for future use. Erase from the oldest unit first.
709
pr_debug("INFTL: deleting empty VUC %d\n", thisVUC);
712
u16 *prevEUN = &inftl->VUtable[thisVUC];
715
/* If the chain is all gone already, we're done */
716
if (thisEUN == BLOCK_NIL) {
717
pr_debug("INFTL: Empty VUC %d for deletion was already absent\n", thisEUN);
721
/* Find oldest unit in chain. */
722
while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
723
BUG_ON(thisEUN >= inftl->nb_blocks);
725
prevEUN = &inftl->PUtable[thisEUN];
729
pr_debug("Deleting EUN %d from VUC %d\n",
732
if (INFTL_formatblock(inftl, thisEUN) < 0) {
734
* Could not erase : mark block as reserved.
736
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
738
/* Correctly erased : mark it as free */
739
inftl->PUtable[thisEUN] = BLOCK_FREE;
740
inftl->numfreeEUNs++;
743
/* Now sort out whatever was pointing to it... */
744
*prevEUN = BLOCK_NIL;
746
/* Ideally we'd actually be responsive to new
747
requests while we're doing this -- if there's
748
free space why should others be made to wait? */
752
inftl->VUtable[thisVUC] = BLOCK_NIL;
755
static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
757
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
758
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
759
struct mtd_info *mtd = inftl->mbd.mtd;
761
int silly = MAX_LOOPS;
763
struct inftl_bci bci;
765
pr_debug("INFTL: INFTL_deleteblock(inftl=%p,"
766
"block=%d)\n", inftl, block);
768
while (thisEUN < inftl->nb_blocks) {
769
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
770
blockofs, 8, &retlen, (char *)&bci) < 0)
771
status = SECTOR_IGNORE;
773
status = bci.Status | bci.Status1;
785
printk(KERN_WARNING "INFTL: unknown status for "
786
"block %d in EUN %d: 0x%x\n",
787
block, thisEUN, status);
792
printk(KERN_WARNING "INFTL: infinite loop in Virtual "
794
block / (inftl->EraseSize / SECTORSIZE));
797
thisEUN = inftl->PUtable[thisEUN];
801
if (thisEUN != BLOCK_NIL) {
802
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
804
if (inftl_read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
806
bci.Status = bci.Status1 = SECTOR_DELETED;
807
if (inftl_write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
809
INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
814
static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
817
struct INFTLrecord *inftl = (void *)mbd;
818
unsigned int writeEUN;
819
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
821
struct inftl_oob oob;
824
pr_debug("INFTL: inftl_writeblock(inftl=%p,block=%ld,"
825
"buffer=%p)\n", inftl, block, buffer);
827
/* Is block all zero? */
828
pend = buffer + SECTORSIZE;
829
for (p = buffer; p < pend && !*p; p++)
833
writeEUN = INFTL_findwriteunit(inftl, block);
835
if (writeEUN == BLOCK_NIL) {
836
printk(KERN_WARNING "inftl_writeblock(): cannot find "
837
"block to write to\n");
839
* If we _still_ haven't got a block to use,
845
memset(&oob, 0xff, sizeof(struct inftl_oob));
846
oob.b.Status = oob.b.Status1 = SECTOR_USED;
848
inftl_write(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
849
blockofs, SECTORSIZE, &retlen, (char *)buffer,
852
* need to write SECTOR_USED flags since they are not written
856
INFTL_deleteblock(inftl, block);
862
static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
865
struct INFTLrecord *inftl = (void *)mbd;
866
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
867
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
868
struct mtd_info *mtd = inftl->mbd.mtd;
870
int silly = MAX_LOOPS;
871
struct inftl_bci bci;
874
pr_debug("INFTL: inftl_readblock(inftl=%p,block=%ld,"
875
"buffer=%p)\n", inftl, block, buffer);
877
while (thisEUN < inftl->nb_blocks) {
878
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
879
blockofs, 8, &retlen, (char *)&bci) < 0)
880
status = SECTOR_IGNORE;
882
status = bci.Status | bci.Status1;
894
printk(KERN_WARNING "INFTL: unknown status for "
895
"block %ld in EUN %d: 0x%04x\n",
896
block, thisEUN, status);
901
printk(KERN_WARNING "INFTL: infinite loop in "
902
"Virtual Unit Chain 0x%lx\n",
903
block / (inftl->EraseSize / SECTORSIZE));
907
thisEUN = inftl->PUtable[thisEUN];
911
if (thisEUN == BLOCK_NIL) {
912
/* The requested block is not on the media, return all 0x00 */
913
memset(buffer, 0, SECTORSIZE);
916
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
917
int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
919
/* Handle corrected bit flips gracefully */
920
if (ret < 0 && !mtd_is_bitflip(ret))
926
static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
928
struct INFTLrecord *inftl = (void *)dev;
930
geo->heads = inftl->heads;
931
geo->sectors = inftl->sectors;
932
geo->cylinders = inftl->cylinders;
937
static struct mtd_blktrans_ops inftl_tr = {
939
.major = INFTL_MAJOR,
940
.part_bits = INFTL_PARTN_BITS,
942
.getgeo = inftl_getgeo,
943
.readsect = inftl_readblock,
944
.writesect = inftl_writeblock,
945
.add_mtd = inftl_add_mtd,
946
.remove_dev = inftl_remove_dev,
947
.owner = THIS_MODULE,
950
static int __init init_inftl(void)
952
return register_mtd_blktrans(&inftl_tr);
955
static void __exit cleanup_inftl(void)
957
deregister_mtd_blktrans(&inftl_tr);
960
module_init(init_inftl);
961
module_exit(cleanup_inftl);
963
MODULE_LICENSE("GPL");
964
MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
965
MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus");