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