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