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