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