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