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