import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / mtd / nftlcore.c
1 /* Linux driver for NAND Flash Translation Layer      */
2 /* (c) 1999 Machine Vision Holdings, Inc.             */
3 /* Author: David Woodhouse <dwmw2@infradead.org>      */
4 /* $Id: nftlcore.c,v 1.1.1.1 2005/04/11 02:50:25 jack Exp $ */
5
6 /*
7   The contents of this file are distributed under the GNU General
8   Public License version 2. The author places no additional
9   restrictions of any kind on it.
10  */
11
12 #define PRERELEASE
13
14 #include <linux/config.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <asm/errno.h>
18 #include <asm/io.h>
19 #include <asm/uaccess.h>
20 #include <linux/miscdevice.h>
21 #include <linux/pci.h>
22 #include <linux/delay.h>
23 #include <linux/slab.h>
24 #include <linux/sched.h>
25 #include <linux/init.h>
26 #include <linux/blkpg.h>
27
28 #ifdef CONFIG_KMOD
29 #include <linux/kmod.h>
30 #endif
31 #include <linux/mtd/mtd.h>
32 #include <linux/mtd/nand.h>
33 #include <linux/mtd/nftl.h>
34 #include <linux/mtd/compatmac.h>
35
36 /* maximum number of loops while examining next block, to have a
37    chance to detect consistency problems (they should never happen
38    because of the checks done in the mounting */
39
40 #define MAX_LOOPS 10000
41
42 /* NFTL block device stuff */
43 #define MAJOR_NR NFTL_MAJOR
44 #define DEVICE_REQUEST nftl_request
45 #define DEVICE_OFF(device)
46
47
48 #include <linux/blk.h>
49 #include <linux/hdreg.h>
50
51 /* Linux-specific block device functions */
52
53 /* I _HATE_ the Linux block device setup more than anything else I've ever
54  *  encountered, except ...
55  */
56
57 static int nftl_sizes[256];
58 static int nftl_blocksizes[256];
59
60 /* .. for the Linux partition table handling. */
61 struct hd_struct part_table[256];
62
63 #if LINUX_VERSION_CODE < 0x20328
64 static void dummy_init (struct gendisk *crap)
65 {}
66 #endif
67
68 static struct gendisk nftl_gendisk = {
69         major:          MAJOR_NR,
70         major_name:     "nftl",
71         minor_shift:    NFTL_PARTN_BITS,        /* Bits to shift to get real from partition */
72         max_p:          (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */
73 #if LINUX_VERSION_CODE < 0x20328
74         max_nr:         MAX_NFTLS,      /* maximum number of real */
75         init:           dummy_init,     /* init function */
76 #endif
77         part:           part_table,     /* hd struct */
78         sizes:          nftl_sizes,     /* block sizes */
79 };
80
81 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
82 #define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
83 #define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
84 #else
85 #define BLK_INC_USE_COUNT do {} while(0)
86 #define BLK_DEC_USE_COUNT do {} while(0)
87 #endif
88
89 struct NFTLrecord *NFTLs[MAX_NFTLS];
90
91 static void NFTL_setup(struct mtd_info *mtd)
92 {
93         int i;
94         struct NFTLrecord *nftl;
95         unsigned long temp;
96         int firstfree = -1;
97
98         DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
99
100         for (i = 0; i < MAX_NFTLS; i++) {
101                 if (!NFTLs[i] && firstfree == -1)
102                         firstfree = i;
103                 else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
104                         /* This is a Spare Media Header for an NFTL we've already found */
105                         DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
106                         return;
107                 }
108         }
109         if (firstfree == -1) {
110                 printk(KERN_WARNING "No more NFTL slot available\n");
111                 return;
112         }
113
114         nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
115         if (!nftl) {
116                 printk(KERN_WARNING "Out of memory for NFTL data structures\n");
117                 return;
118         }
119
120         init_MUTEX(&nftl->mutex);
121
122         nftl->mtd = mtd;
123
124         if (NFTL_mount(nftl) < 0) {
125                 printk(KERN_WARNING "Could not mount NFTL device\n");
126                 kfree(nftl);
127                 return;
128         }
129
130         /* OK, it's a new one. Set up all the data structures. */
131 #ifdef PSYCHO_DEBUG
132         printk("Found new NFTL nftl%c\n", firstfree + 'a');
133 #endif
134
135         /* linux stuff */
136         nftl->usecount = 0;
137         nftl->cylinders = 1024;
138         nftl->heads = 16;
139
140         temp = nftl->cylinders * nftl->heads;
141         nftl->sectors = nftl->nr_sects / temp;
142         if (nftl->nr_sects % temp) {
143                 nftl->sectors++;
144                 temp = nftl->cylinders * nftl->sectors;
145                 nftl->heads = nftl->nr_sects / temp;
146
147                 if (nftl->nr_sects % temp) {
148                         nftl->heads++;
149                         temp = nftl->heads * nftl->sectors;
150                         nftl->cylinders = nftl->nr_sects / temp;
151                 }
152         }
153
154         if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
155                 printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
156                        "match size of 0x%x.\n", nftl->nr_sects);
157                 printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", 
158                        nftl->cylinders, nftl->heads , nftl->sectors, 
159                        (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
160
161                 /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
162         }
163         NFTLs[firstfree] = nftl;
164         /* Finally, set up the block device sizes */
165         nftl_sizes[firstfree * 16] = nftl->nr_sects;
166         //nftl_blocksizes[firstfree*16] = 512;
167         part_table[firstfree * 16].nr_sects = nftl->nr_sects;
168
169         nftl_gendisk.nr_real++;
170
171         /* partition check ... */
172 #if LINUX_VERSION_CODE < 0x20328
173         resetup_one_dev(&nftl_gendisk, firstfree);
174 #else
175         grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects);
176 #endif
177 }
178
179 static void NFTL_unsetup(int i)
180 {
181         struct NFTLrecord *nftl = NFTLs[i];
182
183         DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
184         
185         NFTLs[i] = NULL;
186         
187         if (nftl->ReplUnitTable)
188                 kfree(nftl->ReplUnitTable);
189         if (nftl->EUNtable)
190                 kfree(nftl->EUNtable);
191                       
192         nftl_gendisk.nr_real--;
193         kfree(nftl);
194 }
195
196 /* Search the MTD device for NFTL partitions */
197 static void NFTL_notify_add(struct mtd_info *mtd)
198 {
199         DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
200
201         if (mtd) {
202                 if (!mtd->read_oob) {
203                         /* If this MTD doesn't have out-of-band data,
204                            then there's no point continuing */
205                         DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
206                         return;
207                 }
208                 DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", 
209                       mtd->read, mtd->size, mtd->erasesize);
210
211                 NFTL_setup(mtd);
212         }
213 }
214
215 static void NFTL_notify_remove(struct mtd_info *mtd)
216 {
217         int i;
218
219         for (i = 0; i < MAX_NFTLS; i++) {
220                 if (NFTLs[i] && NFTLs[i]->mtd == mtd)
221                         NFTL_unsetup(i);
222         }
223 }
224
225 #ifdef CONFIG_NFTL_RW
226
227 /* Actual NFTL access routines */
228 /* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
229  *      when the give Virtual Unit Chain
230  */
231 static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
232 {
233         /* For a given Virtual Unit Chain: find or create a free block and
234            add it to the chain */
235         /* We're passed the number of the last EUN in the chain, to save us from
236            having to look it up again */
237         u16 pot = nftl->LastFreeEUN;
238         int silly = nftl->nb_blocks;
239
240         /* Normally, we force a fold to happen before we run out of free blocks completely */
241         if (!desperate && nftl->numfreeEUNs < 2) {
242                 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
243                 return 0xffff;
244         }
245
246         /* Scan for a free block */
247         do {
248                 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
249                         nftl->LastFreeEUN = pot;
250                         nftl->numfreeEUNs--;
251                         return pot;
252                 }
253
254                 /* This will probably point to the MediaHdr unit itself,
255                    right at the beginning of the partition. But that unit
256                    (and the backup unit too) should have the UCI set
257                    up so that it's not selected for overwriting */
258                 if (++pot > nftl->lastEUN)
259                         pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
260
261                 if (!silly--) {
262                         printk("Argh! No free blocks found! LastFreeEUN = %d, "
263                                "FirstEUN = %d\n", nftl->LastFreeEUN, 
264                                le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
265                         return 0xffff;
266                 }
267         } while (pot != nftl->LastFreeEUN);
268
269         return 0xffff;
270 }
271
272 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
273 {
274         u16 BlockMap[MAX_SECTORS_PER_UNIT];
275         unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
276         unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
277         unsigned int thisEUN;
278         int block;
279         int silly;
280         unsigned int targetEUN;
281         struct nftl_oob oob;
282         int inplace = 1;
283         size_t retlen;
284
285         memset(BlockMap, 0xff, sizeof(BlockMap));
286         memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
287
288         thisEUN = nftl->EUNtable[thisVUC];
289
290         if (thisEUN == BLOCK_NIL) {
291                 printk(KERN_WARNING "Trying to fold non-existent "
292                        "Virtual Unit Chain %d!\n", thisVUC);
293                 return BLOCK_NIL;
294         }
295         
296         /* Scan to find the Erase Unit which holds the actual data for each
297            512-byte block within the Chain.
298         */
299         silly = MAX_LOOPS;
300         targetEUN = BLOCK_NIL;
301         while (thisEUN <= nftl->lastEUN ) {
302                 unsigned int status, foldmark;
303
304                 targetEUN = thisEUN;
305                 for (block = 0; block < nftl->EraseSize / 512; block ++) {
306                         MTD_READOOB(nftl->mtd,
307                                     (thisEUN * nftl->EraseSize) + (block * 512),
308                                     16 , &retlen, (char *)&oob);
309                         if (block == 2) {
310                                 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
311                                 if (foldmark == FOLD_MARK_IN_PROGRESS) {
312                                         DEBUG(MTD_DEBUG_LEVEL1, 
313                                               "Write Inhibited on EUN %d\n", thisEUN);
314                                         inplace = 0;
315                                 } else {
316                                         /* There's no other reason not to do inplace,
317                                            except ones that come later. So we don't need
318                                            to preserve inplace */
319                                         inplace = 1;
320                                 }
321                         }
322                         status = oob.b.Status | oob.b.Status1;
323                         BlockLastState[block] = status;
324
325                         switch(status) {
326                         case SECTOR_FREE:
327                                 BlockFreeFound[block] = 1;
328                                 break;
329
330                         case SECTOR_USED:
331                                 if (!BlockFreeFound[block])
332                                         BlockMap[block] = thisEUN;
333                                 else
334                                         printk(KERN_WARNING 
335                                                "SECTOR_USED found after SECTOR_FREE "
336                                                "in Virtual Unit Chain %d for block %d\n",
337                                                thisVUC, block);
338                                 break;
339                         case SECTOR_DELETED:
340                                 if (!BlockFreeFound[block])
341                                         BlockMap[block] = BLOCK_NIL;
342                                 else
343                                         printk(KERN_WARNING 
344                                                "SECTOR_DELETED found after SECTOR_FREE "
345                                                "in Virtual Unit Chain %d for block %d\n",
346                                                thisVUC, block);
347                                 break;
348
349                         case SECTOR_IGNORE:
350                                 break;
351                         default:
352                                 printk("Unknown status for block %d in EUN %d: %x\n",
353                                        block, thisEUN, status);
354                         }
355                 }
356
357                 if (!silly--) {
358                         printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
359                                thisVUC);
360                         return BLOCK_NIL;
361                 }
362                 
363                 thisEUN = nftl->ReplUnitTable[thisEUN];
364         }
365
366         if (inplace) {
367                 /* We're being asked to be a fold-in-place. Check
368                    that all blocks which actually have data associated
369                    with them (i.e. BlockMap[block] != BLOCK_NIL) are 
370                    either already present or SECTOR_FREE in the target
371                    block. If not, we're going to have to fold out-of-place
372                    anyway.
373                 */
374                 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
375                         if (BlockLastState[block] != SECTOR_FREE &&
376                             BlockMap[block] != BLOCK_NIL &&
377                             BlockMap[block] != targetEUN) {
378                                 DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
379                                       "block %d was %x lastEUN, "
380                                       "and is in EUN %d (%s) %d\n",
381                                       thisVUC, block, BlockLastState[block],
382                                       BlockMap[block], 
383                                       BlockMap[block]== targetEUN ? "==" : "!=",
384                                       targetEUN);
385                                 inplace = 0;
386                                 break;
387                         }
388                 }
389
390                 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
391                     pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
392                     BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
393                     SECTOR_FREE) {
394                         DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
395                               "Folding out of place.\n", targetEUN);
396                         inplace = 0;
397                 }
398         }
399         
400         if (!inplace) {
401                 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
402                       "Trying out-of-place\n", thisVUC);
403                 /* We need to find a targetEUN to fold into. */
404                 targetEUN = NFTL_findfreeblock(nftl, 1);
405                 if (targetEUN == BLOCK_NIL) {
406                         /* Ouch. Now we're screwed. We need to do a 
407                            fold-in-place of another chain to make room
408                            for this one. We need a better way of selecting
409                            which chain to fold, because makefreeblock will 
410                            only ask us to fold the same one again.
411                         */
412                         printk(KERN_WARNING
413                                "NFTL_findfreeblock(desperate) returns 0xffff.\n");
414                         return BLOCK_NIL;
415                 }
416         } else {
417             /* We put a fold mark in the chain we are folding only if
418                we fold in place to help the mount check code. If we do
419                not fold in place, it is possible to find the valid
420                chain by selecting the longer one */
421             oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
422             oob.u.c.unused = 0xffffffff;
423             MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 
424                          8, &retlen, (char *)&oob.u);
425         }
426
427         /* OK. We now know the location of every block in the Virtual Unit Chain,
428            and the Erase Unit into which we are supposed to be copying.
429            Go for it.
430         */
431         DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
432         for (block = 0; block < nftl->EraseSize / 512 ; block++) {
433                 unsigned char movebuf[512];
434                 int ret;
435
436                 /* If it's in the target EUN already, or if it's pending write, do nothing */
437                 if (BlockMap[block] == targetEUN ||
438                     (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
439                         continue;
440                 }
441
442                 /* copy only in non free block (free blocks can only
443                    happen in case of media errors or deleted blocks) */
444                 if (BlockMap[block] == BLOCK_NIL)
445                         continue;
446                 
447                 ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
448                                   512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
449                 if (ret < 0) {
450                     ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
451                                       + (block * 512), 512, &retlen,
452                                       movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
453                     if (ret != -EIO) 
454                         printk("Error went away on retry.\n");
455                 }
456                 MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
457                              512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
458         }
459         
460         /* add the header so that it is now a valid chain */
461         oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
462                 = cpu_to_le16(thisVUC);
463         oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
464         
465         MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8, 
466                      8, &retlen, (char *)&oob.u);
467
468         /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
469
470         /* At this point, we have two different chains for this Virtual Unit, and no way to tell 
471            them apart. If we crash now, we get confused. However, both contain the same data, so we
472            shouldn't actually lose data in this case. It's just that when we load up on a medium which
473            has duplicate chains, we need to free one of the chains because it's not necessary any more.
474         */
475         thisEUN = nftl->EUNtable[thisVUC];
476         DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
477
478         /* For each block in the old chain (except the targetEUN of course), 
479            free it and make it available for future use */
480         while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
481                 unsigned int EUNtmp;
482
483                 EUNtmp = nftl->ReplUnitTable[thisEUN];
484
485                 if (NFTL_formatblock(nftl, thisEUN) < 0) {
486                         /* could not erase : mark block as reserved
487                          * FixMe: Update Bad Unit Table on disk
488                          */
489                         nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
490                 } else {
491                         /* correctly erased : mark it as free */
492                         nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
493                         nftl->numfreeEUNs++;
494                 }
495                 thisEUN = EUNtmp;
496         }
497         
498         /* Make this the new start of chain for thisVUC */
499         nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
500         nftl->EUNtable[thisVUC] = targetEUN;
501
502         return targetEUN;
503 }
504
505 u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
506 {
507         /* This is the part that needs some cleverness applied. 
508            For now, I'm doing the minimum applicable to actually
509            get the thing to work.
510            Wear-levelling and other clever stuff needs to be implemented
511            and we also need to do some assessment of the results when
512            the system loses power half-way through the routine.
513         */
514         u16 LongestChain = 0;
515         u16 ChainLength = 0, thislen;
516         u16 chain, EUN;
517
518         for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
519                 EUN = nftl->EUNtable[chain];
520                 thislen = 0;
521
522                 while (EUN <= nftl->lastEUN) {
523                         thislen++;
524                         //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
525                         EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
526                         if (thislen > 0xff00) {
527                                 printk("Endless loop in Virtual Chain %d: Unit %x\n",
528                                        chain, EUN);
529                         }
530                         if (thislen > 0xff10) {
531                                 /* Actually, don't return failure. Just ignore this chain and
532                                    get on with it. */
533                                 thislen = 0;
534                                 break;
535                         }
536                 }
537
538                 if (thislen > ChainLength) {
539                         //printk("New longest chain is %d with length %d\n", chain, thislen);
540                         ChainLength = thislen;
541                         LongestChain = chain;
542                 }
543         }
544
545         if (ChainLength < 2) {
546                 printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
547                        "Failing request\n");
548                 return 0xffff;
549         }
550
551         return NFTL_foldchain (nftl, LongestChain, pendingblock);
552 }
553
554 /* NFTL_findwriteunit: Return the unit number into which we can write 
555                        for this block. Make it available if it isn't already
556 */
557 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
558 {
559         u16 lastEUN;
560         u16 thisVUC = block / (nftl->EraseSize / 512);
561         unsigned int writeEUN;
562         unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
563         size_t retlen;
564         int silly, silly2 = 3;
565         struct nftl_oob oob;
566
567         do {
568                 /* Scan the media to find a unit in the VUC which has
569                    a free space for the block in question.
570                 */
571
572                 /* This condition catches the 0x[7f]fff cases, as well as 
573                    being a sanity check for past-end-of-media access
574                 */
575                 lastEUN = BLOCK_NIL;
576                 writeEUN = nftl->EUNtable[thisVUC];
577                 silly = MAX_LOOPS;
578                 while (writeEUN <= nftl->lastEUN) {
579                         struct nftl_bci bci;
580                         size_t retlen;
581                         unsigned int status;
582
583                         lastEUN = writeEUN;
584
585                         MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
586                                     8, &retlen, (char *)&bci);
587                         
588                         DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
589                               block , writeEUN, le16_to_cpu(bci.Status));
590
591                         status = bci.Status | bci.Status1;
592                         switch(status) {
593                         case SECTOR_FREE:
594                                 return writeEUN;
595
596                         case SECTOR_DELETED:
597                         case SECTOR_USED:
598                         case SECTOR_IGNORE:
599                                 break;
600                         default:
601                                 // Invalid block. Don't use it any more. Must implement.
602                                 break;                  
603                         }
604                         
605                         if (!silly--) { 
606                                 printk(KERN_WARNING
607                                        "Infinite loop in Virtual Unit Chain 0x%x\n",
608                                        thisVUC);
609                                 return 0xffff;
610                         }
611
612                         /* Skip to next block in chain */
613                         writeEUN = nftl->ReplUnitTable[writeEUN];
614                 }
615
616                 /* OK. We didn't find one in the existing chain, or there 
617                    is no existing chain. */
618
619                 /* Try to find an already-free block */
620                 writeEUN = NFTL_findfreeblock(nftl, 0);
621
622                 if (writeEUN == BLOCK_NIL) {
623                         /* That didn't work - there were no free blocks just
624                            waiting to be picked up. We're going to have to fold
625                            a chain to make room.
626                         */
627
628                         /* First remember the start of this chain */
629                         //u16 startEUN = nftl->EUNtable[thisVUC];
630                         
631                         //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
632                         writeEUN = NFTL_makefreeblock(nftl, 0xffff);
633
634                         if (writeEUN == BLOCK_NIL) {
635                                 /* OK, we accept that the above comment is 
636                                    lying - there may have been free blocks
637                                    last time we called NFTL_findfreeblock(),
638                                    but they are reserved for when we're
639                                    desperate. Well, now we're desperate.
640                                 */
641                                 DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
642                                 writeEUN = NFTL_findfreeblock(nftl, 1);
643                         }
644                         if (writeEUN == BLOCK_NIL) {
645                                 /* Ouch. This should never happen - we should
646                                    always be able to make some room somehow. 
647                                    If we get here, we've allocated more storage 
648                                    space than actual media, or our makefreeblock
649                                    routine is missing something.
650                                 */
651                                 printk(KERN_WARNING "Cannot make free space.\n");
652                                 return BLOCK_NIL;
653                         }                       
654                         //printk("Restarting scan\n");
655                         lastEUN = BLOCK_NIL;
656                         continue;
657                 }
658
659                 /* We've found a free block. Insert it into the chain. */
660                 
661                 if (lastEUN != BLOCK_NIL) {
662                     thisVUC |= 0x8000; /* It's a replacement block */
663                 } else {
664                     /* The first block in a new chain */
665                     nftl->EUNtable[thisVUC] = writeEUN;
666                 }
667
668                 /* set up the actual EUN we're writing into */
669                 /* Both in our cache... */
670                 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
671
672                 /* ... and on the flash itself */
673                 MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
674                             &retlen, (char *)&oob.u);
675
676                 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
677
678                 MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
679                              &retlen, (char *)&oob.u);
680
681                 /* we link the new block to the chain only after the
682                    block is ready. It avoids the case where the chain
683                    could point to a free block */
684                 if (lastEUN != BLOCK_NIL) {
685                         /* Both in our cache... */
686                         nftl->ReplUnitTable[lastEUN] = writeEUN;
687                         /* ... and on the flash itself */
688                         MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
689                                     8, &retlen, (char *)&oob.u);
690
691                         oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
692                                 = cpu_to_le16(writeEUN);
693
694                         MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
695                                      8, &retlen, (char *)&oob.u);
696                 }
697
698                 return writeEUN;
699
700         } while (silly2--);
701
702         printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
703                thisVUC);
704         return 0xffff;
705 }
706
707 static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
708 {
709         u16 writeEUN;
710         unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
711         size_t retlen;
712         u8 eccbuf[6];
713
714         writeEUN = NFTL_findwriteunit(nftl, block);
715
716         if (writeEUN == BLOCK_NIL) {
717                 printk(KERN_WARNING
718                        "NFTL_writeblock(): Cannot find block to write to\n");
719                 /* If we _still_ haven't got a block to use, we're screwed */
720                 return 1;
721         }
722
723         MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
724                      512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
725         /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
726
727         return 0;
728 }
729 #endif /* CONFIG_NFTL_RW */
730
731 static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
732 {
733         u16 lastgoodEUN;
734         u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
735         unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
736         unsigned int status;
737         int silly = MAX_LOOPS;
738         size_t retlen;
739         struct nftl_bci bci;
740
741         lastgoodEUN = BLOCK_NIL;
742
743         if (thisEUN != BLOCK_NIL) {
744                 while (thisEUN < nftl->nb_blocks) {
745                         if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
746                                         8, &retlen, (char *)&bci) < 0)
747                                 status = SECTOR_IGNORE;
748                         else
749                                 status = bci.Status | bci.Status1;
750
751                         switch (status) {
752                         case SECTOR_FREE:
753                                 /* no modification of a sector should follow a free sector */
754                                 goto the_end;
755                         case SECTOR_DELETED:
756                                 lastgoodEUN = BLOCK_NIL;
757                                 break;
758                         case SECTOR_USED:
759                                 lastgoodEUN = thisEUN;
760                                 break;
761                         case SECTOR_IGNORE:
762                                 break;
763                         default:
764                                 printk("Unknown status for block %d in EUN %d: %x\n",
765                                        block, thisEUN, status);
766                                 break;
767                         }
768
769                         if (!silly--) {
770                                 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
771                                        block / (nftl->EraseSize / 512));
772                                 return 1;
773                         }
774                         thisEUN = nftl->ReplUnitTable[thisEUN];
775                 }
776         }
777
778  the_end:
779         if (lastgoodEUN == BLOCK_NIL) {
780                 /* the requested block is not on the media, return all 0x00 */
781                 memset(buffer, 0, 512);
782         } else {
783                 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
784                 size_t retlen;
785                 u_char eccbuf[6];
786                 if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
787                         return -EIO;
788         }
789         return 0;
790 }
791
792 static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
793 {
794         struct NFTLrecord *nftl;
795         int p;
796
797         nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS];
798
799         if (!nftl) return -EINVAL;
800
801         switch (cmd) {
802         case HDIO_GETGEO: {
803                 struct hd_geometry g;
804
805                 g.heads = nftl->heads;
806                 g.sectors = nftl->sectors;
807                 g.cylinders = nftl->cylinders;
808                 g.start = part_table[MINOR(inode->i_rdev)].start_sect;
809                 return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
810         }
811         case BLKGETSIZE:   /* Return device size */
812                 return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
813                                 (unsigned long *) arg);
814
815 #ifdef BLKGETSIZE64
816         case BLKGETSIZE64:
817                 return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
818                                 (u64 *)arg);
819 #endif
820
821         case BLKFLSBUF:
822                 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
823                 fsync_dev(inode->i_rdev);
824                 invalidate_buffers(inode->i_rdev);
825                 if (nftl->mtd->sync)
826                         nftl->mtd->sync(nftl->mtd);
827                 return 0;
828
829         case BLKRRPART:
830                 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
831                 if (nftl->usecount > 1) return -EBUSY;
832                 /* 
833                  * We have to flush all buffers and invalidate caches,
834                  * or we won't be able to re-use the partitions,
835                  * if there was a change and we don't want to reboot
836                  */
837                 p = (1<<NFTL_PARTN_BITS) - 1;
838                 while (p-- > 0) {
839                         kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p);
840                         if (part_table[p].nr_sects > 0)
841                                 invalidate_device (devp, 1);
842
843                         part_table[MINOR(inode->i_dev)+p].start_sect = 0;
844                         part_table[MINOR(inode->i_dev)+p].nr_sects = 0;
845                 }
846                 
847 #if LINUX_VERSION_CODE < 0x20328
848                 resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS);
849 #else
850                 grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS,
851                                 1<<NFTL_PARTN_BITS, nftl->nr_sects);
852 #endif
853                 return 0;
854
855 #if (LINUX_VERSION_CODE < 0x20303)              
856         RO_IOCTLS(inode->i_rdev, arg);  /* ref. linux/blk.h */
857 #else
858         case BLKROSET:
859         case BLKROGET:
860         case BLKSSZGET:
861                 return blk_ioctl(inode->i_rdev, cmd, arg);
862 #endif
863
864         default:
865                 return -EINVAL;
866         }
867 }
868
869 void nftl_request(RQFUNC_ARG)
870 {
871         unsigned int dev, block, nsect;
872         struct NFTLrecord *nftl;
873         char *buffer;
874         struct request *req;
875         int res;
876
877         while (1) {
878                 INIT_REQUEST;   /* blk.h */
879                 req = CURRENT;
880                 
881                 /* We can do this because the generic code knows not to
882                    touch the request at the head of the queue */
883                 spin_unlock_irq(&io_request_lock);
884
885                 DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
886                 DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
887                       (req->cmd == READ) ? "Read " : "Write",
888                       req->sector, req->current_nr_sectors);
889
890                 dev = MINOR(req->rq_dev);
891                 block = req->sector;
892                 nsect = req->current_nr_sectors;
893                 buffer = req->buffer;
894                 res = 1; /* succeed */
895
896                 if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) {
897                         /* there is no such partition */
898                         printk("nftl: bad minor number: device = %s\n",
899                                kdevname(req->rq_dev));
900                         res = 0; /* fail */
901                         goto repeat;
902                 }
903                 
904                 nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)];
905                 DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
906                 down(&nftl->mutex);
907                 DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
908
909                 if (block + nsect > part_table[dev].nr_sects) {
910                         /* access past the end of device */
911                         printk("nftl%c%d: bad access: block = %d, count = %d\n",
912                                (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
913                         up(&nftl->mutex);
914                         res = 0; /* fail */
915                         goto repeat;
916                 }
917                 
918                 block += part_table[dev].start_sect;
919                 
920                 if (req->cmd == READ) {
921                         DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
922                               "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
923         
924                         for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
925                                 /* Read a single sector to req->buffer + (512 * i) */
926                                 if (NFTL_readblock(nftl, block, buffer)) {
927                                         DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
928                                         up(&nftl->mutex);
929                                         res = 0;
930                                         goto repeat;
931                                 }
932                         }
933
934                         DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
935                         up(&nftl->mutex);
936                         goto repeat;
937                 } else if (req->cmd == WRITE) {
938                         DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
939                               "(req->nr_sectors == %lx)\n", nsect, block,
940                               req->nr_sectors);
941 #ifdef CONFIG_NFTL_RW
942                         for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
943                                 /* Read a single sector to req->buffer + (512 * i) */
944                                 if (NFTL_writeblock(nftl, block, buffer)) {
945                                         DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
946                                         up(&nftl->mutex);
947                                         res = 0;
948                                         goto repeat;
949                                 }
950                         }
951                         DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
952 #else
953                         res = 0; /* Writes always fail */
954 #endif /* CONFIG_NFTL_RW */
955                         up(&nftl->mutex);
956                         goto repeat;
957                 } else {
958                         DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
959                         up(&nftl->mutex);
960                         res = 0;
961                         goto repeat;
962                 }
963         repeat: 
964                 DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
965                 spin_lock_irq(&io_request_lock);
966                 end_request(res);
967         }
968 }
969
970 static int nftl_open(struct inode *ip, struct file *fp)
971 {
972         int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS;
973         struct NFTLrecord *thisNFTL;
974         thisNFTL = NFTLs[nftlnum];
975
976         DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
977
978 #ifdef CONFIG_KMOD
979         if (!thisNFTL && nftlnum == 0) {
980                 request_module("docprobe");
981                 thisNFTL = NFTLs[nftlnum];
982         }
983 #endif
984         if (!thisNFTL) {
985                 DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", 
986                       nftlnum, ip->i_rdev, ip, fp);
987                 return -ENODEV;
988         }
989
990 #ifndef CONFIG_NFTL_RW
991         if (fp->f_mode & FMODE_WRITE)
992                 return -EROFS;
993 #endif /* !CONFIG_NFTL_RW */
994
995         thisNFTL->usecount++;
996         BLK_INC_USE_COUNT;
997         if (!get_mtd_device(thisNFTL->mtd, -1)) {
998                 BLK_DEC_USE_COUNT;
999                 return -ENXIO;
1000         }
1001
1002         return 0;
1003 }
1004
1005 static int nftl_release(struct inode *inode, struct file *fp)
1006 {
1007         struct NFTLrecord *thisNFTL;
1008
1009         thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
1010
1011         DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
1012
1013         if (thisNFTL->mtd->sync)
1014                 thisNFTL->mtd->sync(thisNFTL->mtd);
1015         thisNFTL->usecount--;
1016         BLK_DEC_USE_COUNT;
1017
1018         put_mtd_device(thisNFTL->mtd);
1019
1020         return 0;
1021 }
1022 #if LINUX_VERSION_CODE < 0x20326
1023 static struct file_operations nftl_fops = {
1024         read:           block_read,
1025         write:          block_write,
1026         ioctl:          nftl_ioctl,
1027         open:           nftl_open,
1028         release:        nftl_release,
1029         fsync:          block_fsync,
1030 };
1031 #else
1032 static struct block_device_operations nftl_fops = 
1033 {
1034 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
1035         owner:          THIS_MODULE,
1036 #endif
1037         open:           nftl_open,
1038         release:        nftl_release,
1039         ioctl:          nftl_ioctl
1040 };
1041 #endif
1042
1043
1044
1045 /****************************************************************************
1046  *
1047  * Module stuff
1048  *
1049  ****************************************************************************/
1050
1051 static struct mtd_notifier nftl_notifier = {
1052         add:    NFTL_notify_add,
1053         remove: NFTL_notify_remove
1054 };
1055
1056 extern char nftlmountrev[];
1057
1058 int __init init_nftl(void)
1059 {
1060         int i;
1061
1062 #ifdef PRERELEASE 
1063         printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.1.1.1 $, nftlmount.c %s\n", nftlmountrev);
1064 #endif
1065
1066         if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
1067                 printk("unable to register NFTL block device on major %d\n", MAJOR_NR);
1068                 return -EBUSY;
1069         } else {
1070                 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
1071
1072                 /* set block size to 1kB each */
1073                 for (i = 0; i < 256; i++) {
1074                         nftl_blocksizes[i] = 1024;
1075                 }
1076                 blksize_size[MAJOR_NR] = nftl_blocksizes;
1077
1078                 add_gendisk(&nftl_gendisk);
1079         }
1080         
1081         register_mtd_user(&nftl_notifier);
1082
1083         return 0;
1084 }
1085
1086 static void __exit cleanup_nftl(void)
1087 {
1088         unregister_mtd_user(&nftl_notifier);
1089         unregister_blkdev(MAJOR_NR, "nftl");
1090         
1091         blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1092
1093         del_gendisk(&nftl_gendisk);
1094 }
1095
1096 module_init(init_nftl);
1097 module_exit(cleanup_nftl);
1098
1099 MODULE_LICENSE("GPL");
1100 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
1101 MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");