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