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