[PATCH] hdaps: support Lenovo ThinkPad T60
[linux-2.6] / drivers / mtd / nftlcore.c
1 /* Linux driver for NAND Flash Translation Layer      */
2 /* (c) 1999 Machine Vision Holdings, Inc.             */
3 /* Author: David Woodhouse <dwmw2@infradead.org>      */
4 /* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */
5
6 /*
7   The contents of this file are distributed under the GNU General
8   Public License version 2. The author places no additional
9   restrictions of any kind on it.
10  */
11
12 #define PRERELEASE
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <asm/errno.h>
17 #include <asm/io.h>
18 #include <asm/uaccess.h>
19 #include <linux/miscdevice.h>
20 #include <linux/pci.h>
21 #include <linux/delay.h>
22 #include <linux/slab.h>
23 #include <linux/sched.h>
24 #include <linux/init.h>
25 #include <linux/hdreg.h>
26
27 #include <linux/kmod.h>
28 #include <linux/mtd/mtd.h>
29 #include <linux/mtd/nand.h>
30 #include <linux/mtd/nftl.h>
31 #include <linux/mtd/blktrans.h>
32
33 /* maximum number of loops while examining next block, to have a
34    chance to detect consistency problems (they should never happen
35    because of the checks done in the mounting */
36
37 #define MAX_LOOPS 10000
38
39
40 static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
41 {
42         struct NFTLrecord *nftl;
43         unsigned long temp;
44
45         if (mtd->type != MTD_NANDFLASH)
46                 return;
47         /* OK, this is moderately ugly.  But probably safe.  Alternatives? */
48         if (memcmp(mtd->name, "DiskOnChip", 10))
49                 return;
50
51         if (!mtd->block_isbad) {
52                 printk(KERN_ERR
53 "NFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
54 "Please use the new diskonchip driver under the NAND subsystem.\n");
55                 return;
56         }
57
58         DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
59
60         nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
61
62         if (!nftl) {
63                 printk(KERN_WARNING "NFTL: out of memory for data structures\n");
64                 return;
65         }
66         memset(nftl, 0, sizeof(*nftl));
67
68         nftl->mbd.mtd = mtd;
69         nftl->mbd.devnum = -1;
70         nftl->mbd.blksize = 512;
71         nftl->mbd.tr = tr;
72
73         if (NFTL_mount(nftl) < 0) {
74                 printk(KERN_WARNING "NFTL: could not mount device\n");
75                 kfree(nftl);
76                 return;
77         }
78
79         /* OK, it's a new one. Set up all the data structures. */
80
81         /* Calculate geometry */
82         nftl->cylinders = 1024;
83         nftl->heads = 16;
84
85         temp = nftl->cylinders * nftl->heads;
86         nftl->sectors = nftl->mbd.size / temp;
87         if (nftl->mbd.size % temp) {
88                 nftl->sectors++;
89                 temp = nftl->cylinders * nftl->sectors;
90                 nftl->heads = nftl->mbd.size / temp;
91
92                 if (nftl->mbd.size % temp) {
93                         nftl->heads++;
94                         temp = nftl->heads * nftl->sectors;
95                         nftl->cylinders = nftl->mbd.size / temp;
96                 }
97         }
98
99         if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
100                 /*
101                   Oh no we don't have
102                    mbd.size == heads * cylinders * sectors
103                 */
104                 printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
105                        "match size of 0x%lx.\n", nftl->mbd.size);
106                 printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
107                         "(== 0x%lx sects)\n",
108                         nftl->cylinders, nftl->heads , nftl->sectors,
109                         (long)nftl->cylinders * (long)nftl->heads *
110                         (long)nftl->sectors );
111         }
112
113         if (add_mtd_blktrans_dev(&nftl->mbd)) {
114                 kfree(nftl->ReplUnitTable);
115                 kfree(nftl->EUNtable);
116                 kfree(nftl);
117                 return;
118         }
119 #ifdef PSYCHO_DEBUG
120         printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
121 #endif
122 }
123
124 static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
125 {
126         struct NFTLrecord *nftl = (void *)dev;
127
128         DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
129
130         del_mtd_blktrans_dev(dev);
131         kfree(nftl->ReplUnitTable);
132         kfree(nftl->EUNtable);
133         kfree(nftl);
134 }
135
136 /*
137  * Read oob data from flash
138  */
139 int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
140                   size_t *retlen, uint8_t *buf)
141 {
142         struct mtd_oob_ops ops;
143         int res;
144
145         ops.mode = MTD_OOB_PLACE;
146         ops.ooboffs = offs & (mtd->writesize - 1);
147         ops.ooblen = len;
148         ops.oobbuf = buf;
149         ops.datbuf = NULL;
150         ops.len = len;
151
152         res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
153         *retlen = ops.retlen;
154         return res;
155 }
156
157 /*
158  * Write oob data to flash
159  */
160 int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
161                    size_t *retlen, uint8_t *buf)
162 {
163         struct mtd_oob_ops ops;
164         int res;
165
166         ops.mode = MTD_OOB_PLACE;
167         ops.ooboffs = offs & (mtd->writesize - 1);
168         ops.ooblen = len;
169         ops.oobbuf = buf;
170         ops.datbuf = NULL;
171         ops.len = len;
172
173         res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
174         *retlen = ops.retlen;
175         return res;
176 }
177
178 /*
179  * Write data and oob to flash
180  */
181 static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
182                       size_t *retlen, uint8_t *buf, uint8_t *oob)
183 {
184         struct mtd_oob_ops ops;
185         int res;
186
187         ops.mode = MTD_OOB_PLACE;
188         ops.ooboffs = offs;
189         ops.ooblen = mtd->oobsize;
190         ops.oobbuf = oob;
191         ops.datbuf = buf;
192         ops.len = len;
193
194         res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
195         *retlen = ops.retlen;
196         return res;
197 }
198
199 #ifdef CONFIG_NFTL_RW
200
201 /* Actual NFTL access routines */
202 /* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
203  *      when the give Virtual Unit Chain
204  */
205 static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
206 {
207         /* For a given Virtual Unit Chain: find or create a free block and
208            add it to the chain */
209         /* We're passed the number of the last EUN in the chain, to save us from
210            having to look it up again */
211         u16 pot = nftl->LastFreeEUN;
212         int silly = nftl->nb_blocks;
213
214         /* Normally, we force a fold to happen before we run out of free blocks completely */
215         if (!desperate && nftl->numfreeEUNs < 2) {
216                 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
217                 return 0xffff;
218         }
219
220         /* Scan for a free block */
221         do {
222                 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
223                         nftl->LastFreeEUN = pot;
224                         nftl->numfreeEUNs--;
225                         return pot;
226                 }
227
228                 /* This will probably point to the MediaHdr unit itself,
229                    right at the beginning of the partition. But that unit
230                    (and the backup unit too) should have the UCI set
231                    up so that it's not selected for overwriting */
232                 if (++pot > nftl->lastEUN)
233                         pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
234
235                 if (!silly--) {
236                         printk("Argh! No free blocks found! LastFreeEUN = %d, "
237                                "FirstEUN = %d\n", nftl->LastFreeEUN,
238                                le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
239                         return 0xffff;
240                 }
241         } while (pot != nftl->LastFreeEUN);
242
243         return 0xffff;
244 }
245
246 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
247 {
248         struct mtd_info *mtd = nftl->mbd.mtd;
249         u16 BlockMap[MAX_SECTORS_PER_UNIT];
250         unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
251         unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
252         unsigned int thisEUN;
253         int block;
254         int silly;
255         unsigned int targetEUN;
256         struct nftl_oob oob;
257         int inplace = 1;
258         size_t retlen;
259
260         memset(BlockMap, 0xff, sizeof(BlockMap));
261         memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
262
263         thisEUN = nftl->EUNtable[thisVUC];
264
265         if (thisEUN == BLOCK_NIL) {
266                 printk(KERN_WARNING "Trying to fold non-existent "
267                        "Virtual Unit Chain %d!\n", thisVUC);
268                 return BLOCK_NIL;
269         }
270
271         /* Scan to find the Erase Unit which holds the actual data for each
272            512-byte block within the Chain.
273         */
274         silly = MAX_LOOPS;
275         targetEUN = BLOCK_NIL;
276         while (thisEUN <= nftl->lastEUN ) {
277                 unsigned int status, foldmark;
278
279                 targetEUN = thisEUN;
280                 for (block = 0; block < nftl->EraseSize / 512; block ++) {
281                         nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
282                                       (block * 512), 16 , &retlen,
283                                       (char *)&oob);
284                         if (block == 2) {
285                                 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
286                                 if (foldmark == FOLD_MARK_IN_PROGRESS) {
287                                         DEBUG(MTD_DEBUG_LEVEL1,
288                                               "Write Inhibited on EUN %d\n", thisEUN);
289                                         inplace = 0;
290                                 } else {
291                                         /* There's no other reason not to do inplace,
292                                            except ones that come later. So we don't need
293                                            to preserve inplace */
294                                         inplace = 1;
295                                 }
296                         }
297                         status = oob.b.Status | oob.b.Status1;
298                         BlockLastState[block] = status;
299
300                         switch(status) {
301                         case SECTOR_FREE:
302                                 BlockFreeFound[block] = 1;
303                                 break;
304
305                         case SECTOR_USED:
306                                 if (!BlockFreeFound[block])
307                                         BlockMap[block] = thisEUN;
308                                 else
309                                         printk(KERN_WARNING
310                                                "SECTOR_USED found after SECTOR_FREE "
311                                                "in Virtual Unit Chain %d for block %d\n",
312                                                thisVUC, block);
313                                 break;
314                         case SECTOR_DELETED:
315                                 if (!BlockFreeFound[block])
316                                         BlockMap[block] = BLOCK_NIL;
317                                 else
318                                         printk(KERN_WARNING
319                                                "SECTOR_DELETED found after SECTOR_FREE "
320                                                "in Virtual Unit Chain %d for block %d\n",
321                                                thisVUC, block);
322                                 break;
323
324                         case SECTOR_IGNORE:
325                                 break;
326                         default:
327                                 printk("Unknown status for block %d in EUN %d: %x\n",
328                                        block, thisEUN, status);
329                         }
330                 }
331
332                 if (!silly--) {
333                         printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
334                                thisVUC);
335                         return BLOCK_NIL;
336                 }
337
338                 thisEUN = nftl->ReplUnitTable[thisEUN];
339         }
340
341         if (inplace) {
342                 /* We're being asked to be a fold-in-place. Check
343                    that all blocks which actually have data associated
344                    with them (i.e. BlockMap[block] != BLOCK_NIL) are
345                    either already present or SECTOR_FREE in the target
346                    block. If not, we're going to have to fold out-of-place
347                    anyway.
348                 */
349                 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
350                         if (BlockLastState[block] != SECTOR_FREE &&
351                             BlockMap[block] != BLOCK_NIL &&
352                             BlockMap[block] != targetEUN) {
353                                 DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
354                                       "block %d was %x lastEUN, "
355                                       "and is in EUN %d (%s) %d\n",
356                                       thisVUC, block, BlockLastState[block],
357                                       BlockMap[block],
358                                       BlockMap[block]== targetEUN ? "==" : "!=",
359                                       targetEUN);
360                                 inplace = 0;
361                                 break;
362                         }
363                 }
364
365                 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
366                     pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
367                     BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
368                     SECTOR_FREE) {
369                         DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
370                               "Folding out of place.\n", targetEUN);
371                         inplace = 0;
372                 }
373         }
374
375         if (!inplace) {
376                 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
377                       "Trying out-of-place\n", thisVUC);
378                 /* We need to find a targetEUN to fold into. */
379                 targetEUN = NFTL_findfreeblock(nftl, 1);
380                 if (targetEUN == BLOCK_NIL) {
381                         /* Ouch. Now we're screwed. We need to do a
382                            fold-in-place of another chain to make room
383                            for this one. We need a better way of selecting
384                            which chain to fold, because makefreeblock will
385                            only ask us to fold the same one again.
386                         */
387                         printk(KERN_WARNING
388                                "NFTL_findfreeblock(desperate) returns 0xffff.\n");
389                         return BLOCK_NIL;
390                 }
391         } else {
392                 /* We put a fold mark in the chain we are folding only if we
393                fold in place to help the mount check code. If we do not fold in
394                place, it is possible to find the valid chain by selecting the
395                longer one */
396                 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
397                 oob.u.c.unused = 0xffffffff;
398                 nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
399                                8, &retlen, (char *)&oob.u);
400         }
401
402         /* OK. We now know the location of every block in the Virtual Unit Chain,
403            and the Erase Unit into which we are supposed to be copying.
404            Go for it.
405         */
406         DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
407         for (block = 0; block < nftl->EraseSize / 512 ; block++) {
408                 unsigned char movebuf[512];
409                 int ret;
410
411                 /* If it's in the target EUN already, or if it's pending write, do nothing */
412                 if (BlockMap[block] == targetEUN ||
413                     (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
414                         continue;
415                 }
416
417                 /* copy only in non free block (free blocks can only
418                    happen in case of media errors or deleted blocks) */
419                 if (BlockMap[block] == BLOCK_NIL)
420                         continue;
421
422                 ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
423                                 512, &retlen, movebuf);
424                 if (ret < 0 && ret != -EUCLEAN) {
425                         ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
426                                         + (block * 512), 512, &retlen,
427                                         movebuf);
428                         if (ret != -EIO)
429                                 printk("Error went away on retry.\n");
430                 }
431                 memset(&oob, 0xff, sizeof(struct nftl_oob));
432                 oob.b.Status = oob.b.Status1 = SECTOR_USED;
433
434                 nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
435                            (block * 512), 512, &retlen, movebuf, (char *)&oob);
436         }
437
438         /* add the header so that it is now a valid chain */
439         oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
440         oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
441
442         nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
443                        8, &retlen, (char *)&oob.u);
444
445         /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
446
447         /* At this point, we have two different chains for this Virtual Unit, and no way to tell
448            them apart. If we crash now, we get confused. However, both contain the same data, so we
449            shouldn't actually lose data in this case. It's just that when we load up on a medium which
450            has duplicate chains, we need to free one of the chains because it's not necessary any more.
451         */
452         thisEUN = nftl->EUNtable[thisVUC];
453         DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
454
455         /* For each block in the old chain (except the targetEUN of course),
456            free it and make it available for future use */
457         while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
458                 unsigned int EUNtmp;
459
460                 EUNtmp = nftl->ReplUnitTable[thisEUN];
461
462                 if (NFTL_formatblock(nftl, thisEUN) < 0) {
463                         /* could not erase : mark block as reserved
464                          */
465                         nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
466                 } else {
467                         /* correctly erased : mark it as free */
468                         nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
469                         nftl->numfreeEUNs++;
470                 }
471                 thisEUN = EUNtmp;
472         }
473
474         /* Make this the new start of chain for thisVUC */
475         nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
476         nftl->EUNtable[thisVUC] = targetEUN;
477
478         return targetEUN;
479 }
480
481 static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
482 {
483         /* This is the part that needs some cleverness applied.
484            For now, I'm doing the minimum applicable to actually
485            get the thing to work.
486            Wear-levelling and other clever stuff needs to be implemented
487            and we also need to do some assessment of the results when
488            the system loses power half-way through the routine.
489         */
490         u16 LongestChain = 0;
491         u16 ChainLength = 0, thislen;
492         u16 chain, EUN;
493
494         for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
495                 EUN = nftl->EUNtable[chain];
496                 thislen = 0;
497
498                 while (EUN <= nftl->lastEUN) {
499                         thislen++;
500                         //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
501                         EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
502                         if (thislen > 0xff00) {
503                                 printk("Endless loop in Virtual Chain %d: Unit %x\n",
504                                        chain, EUN);
505                         }
506                         if (thislen > 0xff10) {
507                                 /* Actually, don't return failure. Just ignore this chain and
508                                    get on with it. */
509                                 thislen = 0;
510                                 break;
511                         }
512                 }
513
514                 if (thislen > ChainLength) {
515                         //printk("New longest chain is %d with length %d\n", chain, thislen);
516                         ChainLength = thislen;
517                         LongestChain = chain;
518                 }
519         }
520
521         if (ChainLength < 2) {
522                 printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
523                        "Failing request\n");
524                 return 0xffff;
525         }
526
527         return NFTL_foldchain (nftl, LongestChain, pendingblock);
528 }
529
530 /* NFTL_findwriteunit: Return the unit number into which we can write
531                        for this block. Make it available if it isn't already
532 */
533 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
534 {
535         u16 lastEUN;
536         u16 thisVUC = block / (nftl->EraseSize / 512);
537         struct mtd_info *mtd = nftl->mbd.mtd;
538         unsigned int writeEUN;
539         unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
540         size_t retlen;
541         int silly, silly2 = 3;
542         struct nftl_oob oob;
543
544         do {
545                 /* Scan the media to find a unit in the VUC which has
546                    a free space for the block in question.
547                 */
548
549                 /* This condition catches the 0x[7f]fff cases, as well as
550                    being a sanity check for past-end-of-media access
551                 */
552                 lastEUN = BLOCK_NIL;
553                 writeEUN = nftl->EUNtable[thisVUC];
554                 silly = MAX_LOOPS;
555                 while (writeEUN <= nftl->lastEUN) {
556                         struct nftl_bci bci;
557                         size_t retlen;
558                         unsigned int status;
559
560                         lastEUN = writeEUN;
561
562                         nftl_read_oob(mtd,
563                                       (writeEUN * nftl->EraseSize) + blockofs,
564                                       8, &retlen, (char *)&bci);
565
566                         DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
567                               block , writeEUN, le16_to_cpu(bci.Status));
568
569                         status = bci.Status | bci.Status1;
570                         switch(status) {
571                         case SECTOR_FREE:
572                                 return writeEUN;
573
574                         case SECTOR_DELETED:
575                         case SECTOR_USED:
576                         case SECTOR_IGNORE:
577                                 break;
578                         default:
579                                 // Invalid block. Don't use it any more. Must implement.
580                                 break;
581                         }
582
583                         if (!silly--) {
584                                 printk(KERN_WARNING
585                                        "Infinite loop in Virtual Unit Chain 0x%x\n",
586                                        thisVUC);
587                                 return 0xffff;
588                         }
589
590                         /* Skip to next block in chain */
591                         writeEUN = nftl->ReplUnitTable[writeEUN];
592                 }
593
594                 /* OK. We didn't find one in the existing chain, or there
595                    is no existing chain. */
596
597                 /* Try to find an already-free block */
598                 writeEUN = NFTL_findfreeblock(nftl, 0);
599
600                 if (writeEUN == BLOCK_NIL) {
601                         /* That didn't work - there were no free blocks just
602                            waiting to be picked up. We're going to have to fold
603                            a chain to make room.
604                         */
605
606                         /* First remember the start of this chain */
607                         //u16 startEUN = nftl->EUNtable[thisVUC];
608
609                         //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
610                         writeEUN = NFTL_makefreeblock(nftl, 0xffff);
611
612                         if (writeEUN == BLOCK_NIL) {
613                                 /* OK, we accept that the above comment is
614                                    lying - there may have been free blocks
615                                    last time we called NFTL_findfreeblock(),
616                                    but they are reserved for when we're
617                                    desperate. Well, now we're desperate.
618                                 */
619                                 DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
620                                 writeEUN = NFTL_findfreeblock(nftl, 1);
621                         }
622                         if (writeEUN == BLOCK_NIL) {
623                                 /* Ouch. This should never happen - we should
624                                    always be able to make some room somehow.
625                                    If we get here, we've allocated more storage
626                                    space than actual media, or our makefreeblock
627                                    routine is missing something.
628                                 */
629                                 printk(KERN_WARNING "Cannot make free space.\n");
630                                 return BLOCK_NIL;
631                         }
632                         //printk("Restarting scan\n");
633                         lastEUN = BLOCK_NIL;
634                         continue;
635                 }
636
637                 /* We've found a free block. Insert it into the chain. */
638
639                 if (lastEUN != BLOCK_NIL) {
640                         thisVUC |= 0x8000; /* It's a replacement block */
641                 } else {
642                         /* The first block in a new chain */
643                         nftl->EUNtable[thisVUC] = writeEUN;
644                 }
645
646                 /* set up the actual EUN we're writing into */
647                 /* Both in our cache... */
648                 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
649
650                 /* ... and on the flash itself */
651                 nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
652                               &retlen, (char *)&oob.u);
653
654                 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
655
656                 nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
657                                &retlen, (char *)&oob.u);
658
659                 /* we link the new block to the chain only after the
660                    block is ready. It avoids the case where the chain
661                    could point to a free block */
662                 if (lastEUN != BLOCK_NIL) {
663                         /* Both in our cache... */
664                         nftl->ReplUnitTable[lastEUN] = writeEUN;
665                         /* ... and on the flash itself */
666                         nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
667                                       8, &retlen, (char *)&oob.u);
668
669                         oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
670                                 = cpu_to_le16(writeEUN);
671
672                         nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
673                                        8, &retlen, (char *)&oob.u);
674                 }
675
676                 return writeEUN;
677
678         } while (silly2--);
679
680         printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
681                thisVUC);
682         return 0xffff;
683 }
684
685 static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
686                            char *buffer)
687 {
688         struct NFTLrecord *nftl = (void *)mbd;
689         u16 writeEUN;
690         unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
691         size_t retlen;
692         struct nftl_oob oob;
693
694         writeEUN = NFTL_findwriteunit(nftl, block);
695
696         if (writeEUN == BLOCK_NIL) {
697                 printk(KERN_WARNING
698                        "NFTL_writeblock(): Cannot find block to write to\n");
699                 /* If we _still_ haven't got a block to use, we're screwed */
700                 return 1;
701         }
702
703         memset(&oob, 0xff, sizeof(struct nftl_oob));
704         oob.b.Status = oob.b.Status1 = SECTOR_USED;
705
706         nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
707                    512, &retlen, (char *)buffer, (char *)&oob);
708         return 0;
709 }
710 #endif /* CONFIG_NFTL_RW */
711
712 static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
713                           char *buffer)
714 {
715         struct NFTLrecord *nftl = (void *)mbd;
716         struct mtd_info *mtd = nftl->mbd.mtd;
717         u16 lastgoodEUN;
718         u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
719         unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
720         unsigned int status;
721         int silly = MAX_LOOPS;
722         size_t retlen;
723         struct nftl_bci bci;
724
725         lastgoodEUN = BLOCK_NIL;
726
727         if (thisEUN != BLOCK_NIL) {
728                 while (thisEUN < nftl->nb_blocks) {
729                         if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
730                                           blockofs, 8, &retlen,
731                                           (char *)&bci) < 0)
732                                 status = SECTOR_IGNORE;
733                         else
734                                 status = bci.Status | bci.Status1;
735
736                         switch (status) {
737                         case SECTOR_FREE:
738                                 /* no modification of a sector should follow a free sector */
739                                 goto the_end;
740                         case SECTOR_DELETED:
741                                 lastgoodEUN = BLOCK_NIL;
742                                 break;
743                         case SECTOR_USED:
744                                 lastgoodEUN = thisEUN;
745                                 break;
746                         case SECTOR_IGNORE:
747                                 break;
748                         default:
749                                 printk("Unknown status for block %ld in EUN %d: %x\n",
750                                        block, thisEUN, status);
751                                 break;
752                         }
753
754                         if (!silly--) {
755                                 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
756                                        block / (nftl->EraseSize / 512));
757                                 return 1;
758                         }
759                         thisEUN = nftl->ReplUnitTable[thisEUN];
760                 }
761         }
762
763  the_end:
764         if (lastgoodEUN == BLOCK_NIL) {
765                 /* the requested block is not on the media, return all 0x00 */
766                 memset(buffer, 0, 512);
767         } else {
768                 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
769                 size_t retlen;
770                 int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
771
772                 if (res < 0 && res != -EUCLEAN)
773                         return -EIO;
774         }
775         return 0;
776 }
777
778 static int nftl_getgeo(struct mtd_blktrans_dev *dev,  struct hd_geometry *geo)
779 {
780         struct NFTLrecord *nftl = (void *)dev;
781
782         geo->heads = nftl->heads;
783         geo->sectors = nftl->sectors;
784         geo->cylinders = nftl->cylinders;
785
786         return 0;
787 }
788
789 /****************************************************************************
790  *
791  * Module stuff
792  *
793  ****************************************************************************/
794
795
796 static struct mtd_blktrans_ops nftl_tr = {
797         .name           = "nftl",
798         .major          = NFTL_MAJOR,
799         .part_bits      = NFTL_PARTN_BITS,
800         .getgeo         = nftl_getgeo,
801         .readsect       = nftl_readblock,
802 #ifdef CONFIG_NFTL_RW
803         .writesect      = nftl_writeblock,
804 #endif
805         .add_mtd        = nftl_add_mtd,
806         .remove_dev     = nftl_remove_dev,
807         .owner          = THIS_MODULE,
808 };
809
810 extern char nftlmountrev[];
811
812 static int __init init_nftl(void)
813 {
814         printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev);
815
816         return register_mtd_blktrans(&nftl_tr);
817 }
818
819 static void __exit cleanup_nftl(void)
820 {
821         deregister_mtd_blktrans(&nftl_tr);
822 }
823
824 module_init(init_nftl);
825 module_exit(cleanup_nftl);
826
827 MODULE_LICENSE("GPL");
828 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
829 MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");