[MTD] Remove silly MTD_WRITE/READ macros
[safe/jmp/linux-2.6] / drivers / mtd / inftlcore.c
1 /*
2  * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
3  *
4  * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
5  *
6  * Based heavily on the nftlcore.c code which is:
7  * (c) 1999 Machine Vision Holdings, Inc.
8  * Author: David Woodhouse <dwmw2@infradead.org>
9  *
10  * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include <linux/config.h>
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/delay.h>
31 #include <linux/slab.h>
32 #include <linux/sched.h>
33 #include <linux/init.h>
34 #include <linux/kmod.h>
35 #include <linux/hdreg.h>
36 #include <linux/mtd/mtd.h>
37 #include <linux/mtd/nftl.h>
38 #include <linux/mtd/inftl.h>
39 #include <linux/mtd/nand.h>
40 #include <asm/uaccess.h>
41 #include <asm/errno.h>
42 #include <asm/io.h>
43
44 /*
45  * Maximum number of loops while examining next block, to have a
46  * chance to detect consistency problems (they should never happen
47  * because of the checks done in the mounting.
48  */
49 #define MAX_LOOPS 10000
50
51 static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
52 {
53         struct INFTLrecord *inftl;
54         unsigned long temp;
55
56         if (mtd->type != MTD_NANDFLASH)
57                 return;
58         /* OK, this is moderately ugly.  But probably safe.  Alternatives? */
59         if (memcmp(mtd->name, "DiskOnChip", 10))
60                 return;
61
62         if (!mtd->block_isbad) {
63                 printk(KERN_ERR
64 "INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
65 "Please use the new diskonchip driver under the NAND subsystem.\n");
66                 return;
67         }
68
69         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
70
71         inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
72
73         if (!inftl) {
74                 printk(KERN_WARNING "INFTL: Out of memory for data structures\n");
75                 return;
76         }
77         memset(inftl, 0, sizeof(*inftl));
78
79         inftl->mbd.mtd = mtd;
80         inftl->mbd.devnum = -1;
81         inftl->mbd.blksize = 512;
82         inftl->mbd.tr = tr;
83
84         if (INFTL_mount(inftl) < 0) {
85                 printk(KERN_WARNING "INFTL: could not mount device\n");
86                 kfree(inftl);
87                 return;
88         }
89
90         /* OK, it's a new one. Set up all the data structures. */
91
92         /* Calculate geometry */
93         inftl->cylinders = 1024;
94         inftl->heads = 16;
95
96         temp = inftl->cylinders * inftl->heads;
97         inftl->sectors = inftl->mbd.size / temp;
98         if (inftl->mbd.size % temp) {
99                 inftl->sectors++;
100                 temp = inftl->cylinders * inftl->sectors;
101                 inftl->heads = inftl->mbd.size / temp;
102
103                 if (inftl->mbd.size % temp) {
104                         inftl->heads++;
105                         temp = inftl->heads * inftl->sectors;
106                         inftl->cylinders = inftl->mbd.size / temp;
107                 }
108         }
109
110         if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
111                 /*
112                   Oh no we don't have
113                    mbd.size == heads * cylinders * sectors
114                 */
115                 printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
116                        "match size of 0x%lx.\n", inftl->mbd.size);
117                 printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
118                         "(== 0x%lx sects)\n",
119                         inftl->cylinders, inftl->heads , inftl->sectors,
120                         (long)inftl->cylinders * (long)inftl->heads *
121                         (long)inftl->sectors );
122         }
123
124         if (add_mtd_blktrans_dev(&inftl->mbd)) {
125                 kfree(inftl->PUtable);
126                 kfree(inftl->VUtable);
127                 kfree(inftl);
128                 return;
129         }
130 #ifdef PSYCHO_DEBUG
131         printk(KERN_INFO "INFTL: Found new inftl%c\n", inftl->mbd.devnum + 'a');
132 #endif
133         return;
134 }
135
136 static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
137 {
138         struct INFTLrecord *inftl = (void *)dev;
139
140         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum);
141
142         del_mtd_blktrans_dev(dev);
143
144         kfree(inftl->PUtable);
145         kfree(inftl->VUtable);
146         kfree(inftl);
147 }
148
149 /*
150  * Actual INFTL access routines.
151  */
152
153 /*
154  * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
155  *      This function is used when the give Virtual Unit Chain.
156  */
157 static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
158 {
159         u16 pot = inftl->LastFreeEUN;
160         int silly = inftl->nb_blocks;
161
162         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p,"
163                 "desperate=%d)\n", inftl, desperate);
164
165         /*
166          * Normally, we force a fold to happen before we run out of free
167          * blocks completely.
168          */
169         if (!desperate && inftl->numfreeEUNs < 2) {
170                 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
171                         "EUNs (%d)\n", inftl->numfreeEUNs);
172                 return 0xffff;
173         }
174
175         /* Scan for a free block */
176         do {
177                 if (inftl->PUtable[pot] == BLOCK_FREE) {
178                         inftl->LastFreeEUN = pot;
179                         return pot;
180                 }
181
182                 if (++pot > inftl->lastEUN)
183                         pot = 0;
184
185                 if (!silly--) {
186                         printk(KERN_WARNING "INFTL: no free blocks found!  "
187                                 "EUN range = %d - %d\n", 0, inftl->LastFreeEUN);
188                         return BLOCK_NIL;
189                 }
190         } while (pot != inftl->LastFreeEUN);
191
192         return BLOCK_NIL;
193 }
194
195 static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock)
196 {
197         u16 BlockMap[MAX_SECTORS_PER_UNIT];
198         unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
199         unsigned int thisEUN, prevEUN, status;
200         struct mtd_info *mtd = inftl->mbd.mtd;
201         int block, silly;
202         unsigned int targetEUN;
203         struct inftl_oob oob;
204         size_t retlen;
205
206         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,"
207                 "pending=%d)\n", inftl, thisVUC, pendingblock);
208
209         memset(BlockMap, 0xff, sizeof(BlockMap));
210         memset(BlockDeleted, 0, sizeof(BlockDeleted));
211
212         thisEUN = targetEUN = inftl->VUtable[thisVUC];
213
214         if (thisEUN == BLOCK_NIL) {
215                 printk(KERN_WARNING "INFTL: trying to fold non-existent "
216                        "Virtual Unit Chain %d!\n", thisVUC);
217                 return BLOCK_NIL;
218         }
219
220         /*
221          * Scan to find the Erase Unit which holds the actual data for each
222          * 512-byte block within the Chain.
223          */
224         silly = MAX_LOOPS;
225         while (thisEUN < inftl->nb_blocks) {
226                 for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
227                         if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
228                                 continue;
229
230                         if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize)
231                                           + (block * SECTORSIZE), 16 , &retlen,
232                                           (char *)&oob) < 0)
233                                 status = SECTOR_IGNORE;
234                         else
235                                 status = oob.b.Status | oob.b.Status1;
236
237                         switch(status) {
238                         case SECTOR_FREE:
239                         case SECTOR_IGNORE:
240                                 break;
241                         case SECTOR_USED:
242                                 BlockMap[block] = thisEUN;
243                                 continue;
244                         case SECTOR_DELETED:
245                                 BlockDeleted[block] = 1;
246                                 continue;
247                         default:
248                                 printk(KERN_WARNING "INFTL: unknown status "
249                                         "for block %d in EUN %d: %x\n",
250                                         block, thisEUN, status);
251                                 break;
252                         }
253                 }
254
255                 if (!silly--) {
256                         printk(KERN_WARNING "INFTL: infinite loop in Virtual "
257                                 "Unit Chain 0x%x\n", thisVUC);
258                         return BLOCK_NIL;
259                 }
260
261                 thisEUN = inftl->PUtable[thisEUN];
262         }
263
264         /*
265          * OK. We now know the location of every block in the Virtual Unit
266          * Chain, and the Erase Unit into which we are supposed to be copying.
267          * Go for it.
268          */
269         DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n",
270                 thisVUC, targetEUN);
271
272         for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {
273                 unsigned char movebuf[SECTORSIZE];
274                 int ret;
275
276                 /*
277                  * If it's in the target EUN already, or if it's pending write,
278                  * do nothing.
279                  */
280                 if (BlockMap[block] == targetEUN || (pendingblock ==
281                     (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) {
282                         continue;
283                 }
284
285                 /*
286                  * Copy only in non free block (free blocks can only
287                  * happen in case of media errors or deleted blocks).
288                  */
289                 if (BlockMap[block] == BLOCK_NIL)
290                         continue;
291
292                 ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
293                                 (block * SECTORSIZE), SECTORSIZE, &retlen,
294                                 movebuf);
295                 if (ret < 0) {
296                         ret = mtd->read(mtd,
297                                         (inftl->EraseSize * BlockMap[block]) +
298                                         (block * SECTORSIZE), SECTORSIZE,
299                                         &retlen, movebuf);
300                         if (ret != -EIO)
301                                 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
302                                       "away on retry?\n");
303                 }
304                 memset(&oob, 0xff, sizeof(struct inftl_oob));
305                 oob.b.Status = oob.b.Status1 = SECTOR_USED;
306
307                 nand_write_raw(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
308                                (block * SECTORSIZE), SECTORSIZE, &retlen,
309                                movebuf, (char *)&oob);
310         }
311
312         /*
313          * Newest unit in chain now contains data from _all_ older units.
314          * So go through and erase each unit in chain, oldest first. (This
315          * is important, by doing oldest first if we crash/reboot then it
316          * it is relatively simple to clean up the mess).
317          */
318         DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n",
319                 thisVUC);
320
321         for (;;) {
322                 /* Find oldest unit in chain. */
323                 thisEUN = inftl->VUtable[thisVUC];
324                 prevEUN = BLOCK_NIL;
325                 while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
326                         prevEUN = thisEUN;
327                         thisEUN = inftl->PUtable[thisEUN];
328                 }
329
330                 /* Check if we are all done */
331                 if (thisEUN == targetEUN)
332                         break;
333
334                 if (INFTL_formatblock(inftl, thisEUN) < 0) {
335                         /*
336                          * Could not erase : mark block as reserved.
337                          */
338                         inftl->PUtable[thisEUN] = BLOCK_RESERVED;
339                 } else {
340                         /* Correctly erased : mark it as free */
341                         inftl->PUtable[thisEUN] = BLOCK_FREE;
342                         inftl->PUtable[prevEUN] = BLOCK_NIL;
343                         inftl->numfreeEUNs++;
344                 }
345         }
346
347         return targetEUN;
348 }
349
350 static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
351 {
352         /*
353          * This is the part that needs some cleverness applied.
354          * For now, I'm doing the minimum applicable to actually
355          * get the thing to work.
356          * Wear-levelling and other clever stuff needs to be implemented
357          * and we also need to do some assessment of the results when
358          * the system loses power half-way through the routine.
359          */
360         u16 LongestChain = 0;
361         u16 ChainLength = 0, thislen;
362         u16 chain, EUN;
363
364         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p,"
365                 "pending=%d)\n", inftl, pendingblock);
366
367         for (chain = 0; chain < inftl->nb_blocks; chain++) {
368                 EUN = inftl->VUtable[chain];
369                 thislen = 0;
370
371                 while (EUN <= inftl->lastEUN) {
372                         thislen++;
373                         EUN = inftl->PUtable[EUN];
374                         if (thislen > 0xff00) {
375                                 printk(KERN_WARNING "INFTL: endless loop in "
376                                         "Virtual Chain %d: Unit %x\n",
377                                         chain, EUN);
378                                 /*
379                                  * Actually, don't return failure.
380                                  * Just ignore this chain and get on with it.
381                                  */
382                                 thislen = 0;
383                                 break;
384                         }
385                 }
386
387                 if (thislen > ChainLength) {
388                         ChainLength = thislen;
389                         LongestChain = chain;
390                 }
391         }
392
393         if (ChainLength < 2) {
394                 printk(KERN_WARNING "INFTL: no Virtual Unit Chains available "
395                         "for folding. Failing request\n");
396                 return BLOCK_NIL;
397         }
398
399         return INFTL_foldchain(inftl, LongestChain, pendingblock);
400 }
401
402 static int nrbits(unsigned int val, int bitcount)
403 {
404         int i, total = 0;
405
406         for (i = 0; (i < bitcount); i++)
407                 total += (((0x1 << i) & val) ? 1 : 0);
408         return total;
409 }
410
411 /*
412  * INFTL_findwriteunit: Return the unit number into which we can write
413  *                      for this block. Make it available if it isn't already.
414  */
415 static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
416 {
417         unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE);
418         unsigned int thisEUN, writeEUN, prev_block, status;
419         unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1);
420         struct mtd_info *mtd = inftl->mbd.mtd;
421         struct inftl_oob oob;
422         struct inftl_bci bci;
423         unsigned char anac, nacs, parity;
424         size_t retlen;
425         int silly, silly2 = 3;
426
427         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p,"
428                 "block=%d)\n", inftl, block);
429
430         do {
431                 /*
432                  * Scan the media to find a unit in the VUC which has
433                  * a free space for the block in question.
434                  */
435                 writeEUN = BLOCK_NIL;
436                 thisEUN = inftl->VUtable[thisVUC];
437                 silly = MAX_LOOPS;
438
439                 while (thisEUN <= inftl->lastEUN) {
440                         mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) +
441                                       blockofs, 8, &retlen, (char *)&bci);
442
443                         status = bci.Status | bci.Status1;
444                         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
445                                 "EUN %d is %x\n", block , writeEUN, status);
446
447                         switch(status) {
448                         case SECTOR_FREE:
449                                 writeEUN = thisEUN;
450                                 break;
451                         case SECTOR_DELETED:
452                         case SECTOR_USED:
453                                 /* Can't go any further */
454                                 goto hitused;
455                         case SECTOR_IGNORE:
456                                 break;
457                         default:
458                                 /*
459                                  * Invalid block. Don't use it any more.
460                                  * Must implement.
461                                  */
462                                 break;
463                         }
464
465                         if (!silly--) {
466                                 printk(KERN_WARNING "INFTL: infinite loop in "
467                                         "Virtual Unit Chain 0x%x\n", thisVUC);
468                                 return 0xffff;
469                         }
470
471                         /* Skip to next block in chain */
472                         thisEUN = inftl->PUtable[thisEUN];
473                 }
474
475 hitused:
476                 if (writeEUN != BLOCK_NIL)
477                         return writeEUN;
478
479
480                 /*
481                  * OK. We didn't find one in the existing chain, or there
482                  * is no existing chain. Allocate a new one.
483                  */
484                 writeEUN = INFTL_findfreeblock(inftl, 0);
485
486                 if (writeEUN == BLOCK_NIL) {
487                         /*
488                          * That didn't work - there were no free blocks just
489                          * waiting to be picked up. We're going to have to fold
490                          * a chain to make room.
491                          */
492                         thisEUN = INFTL_makefreeblock(inftl, 0xffff);
493
494                         /*
495                          * Hopefully we free something, lets try again.
496                          * This time we are desperate...
497                          */
498                         DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 "
499                                 "to find free EUN to accommodate write to "
500                                 "VUC %d\n", thisVUC);
501                         writeEUN = INFTL_findfreeblock(inftl, 1);
502                         if (writeEUN == BLOCK_NIL) {
503                                 /*
504                                  * Ouch. This should never happen - we should
505                                  * always be able to make some room somehow.
506                                  * If we get here, we've allocated more storage
507                                  * space than actual media, or our makefreeblock
508                                  * routine is missing something.
509                                  */
510                                 printk(KERN_WARNING "INFTL: cannot make free "
511                                         "space.\n");
512 #ifdef DEBUG
513                                 INFTL_dumptables(inftl);
514                                 INFTL_dumpVUchains(inftl);
515 #endif
516                                 return BLOCK_NIL;
517                         }
518                 }
519
520                 /*
521                  * Insert new block into virtual chain. Firstly update the
522                  * block headers in flash...
523                  */
524                 anac = 0;
525                 nacs = 0;
526                 thisEUN = inftl->VUtable[thisVUC];
527                 if (thisEUN != BLOCK_NIL) {
528                         mtd->read_oob(mtd, thisEUN * inftl->EraseSize
529                                       + 8, 8, &retlen, (char *)&oob.u);
530                         anac = oob.u.a.ANAC + 1;
531                         nacs = oob.u.a.NACs + 1;
532                 }
533
534                 prev_block = inftl->VUtable[thisVUC];
535                 if (prev_block < inftl->nb_blocks)
536                         prev_block -= inftl->firstEUN;
537
538                 parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0;
539                 parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
540                 parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
541                 parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
542
543                 oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
544                 oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
545                 oob.u.a.ANAC = anac;
546                 oob.u.a.NACs = nacs;
547                 oob.u.a.parityPerField = parity;
548                 oob.u.a.discarded = 0xaa;
549
550                 mtd->write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8,
551                                &retlen, (char *)&oob.u);
552
553                 /* Also back up header... */
554                 oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);
555                 oob.u.b.prevUnitNo = cpu_to_le16(prev_block);
556                 oob.u.b.ANAC = anac;
557                 oob.u.b.NACs = nacs;
558                 oob.u.b.parityPerField = parity;
559                 oob.u.b.discarded = 0xaa;
560
561                 mtd->write_oob(mtd, writeEUN * inftl->EraseSize +
562                                SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
563
564                 inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
565                 inftl->VUtable[thisVUC] = writeEUN;
566
567                 inftl->numfreeEUNs--;
568                 return writeEUN;
569
570         } while (silly2--);
571
572         printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
573                 "Unit Chain 0x%x\n", thisVUC);
574         return 0xffff;
575 }
576
577 /*
578  * Given a Virtual Unit Chain, see if it can be deleted, and if so do it.
579  */
580 static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
581 {
582         struct mtd_info *mtd = inftl->mbd.mtd;
583         unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];
584         unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
585         unsigned int thisEUN, status;
586         int block, silly;
587         struct inftl_bci bci;
588         size_t retlen;
589
590         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p,"
591                 "thisVUC=%d)\n", inftl, thisVUC);
592
593         memset(BlockUsed, 0, sizeof(BlockUsed));
594         memset(BlockDeleted, 0, sizeof(BlockDeleted));
595
596         thisEUN = inftl->VUtable[thisVUC];
597         if (thisEUN == BLOCK_NIL) {
598                 printk(KERN_WARNING "INFTL: trying to delete non-existent "
599                        "Virtual Unit Chain %d!\n", thisVUC);
600                 return;
601         }
602
603         /*
604          * Scan through the Erase Units to determine whether any data is in
605          * each of the 512-byte blocks within the Chain.
606          */
607         silly = MAX_LOOPS;
608         while (thisEUN < inftl->nb_blocks) {
609                 for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) {
610                         if (BlockUsed[block] || BlockDeleted[block])
611                                 continue;
612
613                         if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize)
614                                           + (block * SECTORSIZE), 8 , &retlen,
615                                           (char *)&bci) < 0)
616                                 status = SECTOR_IGNORE;
617                         else
618                                 status = bci.Status | bci.Status1;
619
620                         switch(status) {
621                         case SECTOR_FREE:
622                         case SECTOR_IGNORE:
623                                 break;
624                         case SECTOR_USED:
625                                 BlockUsed[block] = 1;
626                                 continue;
627                         case SECTOR_DELETED:
628                                 BlockDeleted[block] = 1;
629                                 continue;
630                         default:
631                                 printk(KERN_WARNING "INFTL: unknown status "
632                                         "for block %d in EUN %d: 0x%x\n",
633                                         block, thisEUN, status);
634                         }
635                 }
636
637                 if (!silly--) {
638                         printk(KERN_WARNING "INFTL: infinite loop in Virtual "
639                                 "Unit Chain 0x%x\n", thisVUC);
640                         return;
641                 }
642
643                 thisEUN = inftl->PUtable[thisEUN];
644         }
645
646         for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++)
647                 if (BlockUsed[block])
648                         return;
649
650         /*
651          * For each block in the chain free it and make it available
652          * for future use. Erase from the oldest unit first.
653          */
654         DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC);
655
656         for (;;) {
657                 u16 *prevEUN = &inftl->VUtable[thisVUC];
658                 thisEUN = *prevEUN;
659
660                 /* If the chain is all gone already, we're done */
661                 if (thisEUN == BLOCK_NIL) {
662                         DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN);
663                         return;
664                 }
665
666                 /* Find oldest unit in chain. */
667                 while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
668                         BUG_ON(thisEUN >= inftl->nb_blocks);
669
670                         prevEUN = &inftl->PUtable[thisEUN];
671                         thisEUN = *prevEUN;
672                 }
673
674                 DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",
675                       thisEUN, thisVUC);
676
677                 if (INFTL_formatblock(inftl, thisEUN) < 0) {
678                         /*
679                          * Could not erase : mark block as reserved.
680                          */
681                         inftl->PUtable[thisEUN] = BLOCK_RESERVED;
682                 } else {
683                         /* Correctly erased : mark it as free */
684                         inftl->PUtable[thisEUN] = BLOCK_FREE;
685                         inftl->numfreeEUNs++;
686                 }
687
688                 /* Now sort out whatever was pointing to it... */
689                 *prevEUN = BLOCK_NIL;
690
691                 /* Ideally we'd actually be responsive to new
692                    requests while we're doing this -- if there's
693                    free space why should others be made to wait? */
694                 cond_resched();
695         }
696
697         inftl->VUtable[thisVUC] = BLOCK_NIL;
698 }
699
700 static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
701 {
702         unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
703         unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
704         struct mtd_info *mtd = inftl->mbd.mtd;
705         unsigned int status;
706         int silly = MAX_LOOPS;
707         size_t retlen;
708         struct inftl_bci bci;
709
710         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p,"
711                 "block=%d)\n", inftl, block);
712
713         while (thisEUN < inftl->nb_blocks) {
714                 if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) +
715                                   blockofs, 8, &retlen, (char *)&bci) < 0)
716                         status = SECTOR_IGNORE;
717                 else
718                         status = bci.Status | bci.Status1;
719
720                 switch (status) {
721                 case SECTOR_FREE:
722                 case SECTOR_IGNORE:
723                         break;
724                 case SECTOR_DELETED:
725                         thisEUN = BLOCK_NIL;
726                         goto foundit;
727                 case SECTOR_USED:
728                         goto foundit;
729                 default:
730                         printk(KERN_WARNING "INFTL: unknown status for "
731                                 "block %d in EUN %d: 0x%x\n",
732                                 block, thisEUN, status);
733                         break;
734                 }
735
736                 if (!silly--) {
737                         printk(KERN_WARNING "INFTL: infinite loop in Virtual "
738                                 "Unit Chain 0x%x\n",
739                                 block / (inftl->EraseSize / SECTORSIZE));
740                         return 1;
741                 }
742                 thisEUN = inftl->PUtable[thisEUN];
743         }
744
745 foundit:
746         if (thisEUN != BLOCK_NIL) {
747                 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
748
749                 if (mtd->read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
750                         return -EIO;
751                 bci.Status = bci.Status1 = SECTOR_DELETED;
752                 if (mtd->write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
753                         return -EIO;
754                 INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
755         }
756         return 0;
757 }
758
759 static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
760                             char *buffer)
761 {
762         struct INFTLrecord *inftl = (void *)mbd;
763         unsigned int writeEUN;
764         unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
765         size_t retlen;
766         struct inftl_oob oob;
767         char *p, *pend;
768
769         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld,"
770                 "buffer=%p)\n", inftl, block, buffer);
771
772         /* Is block all zero? */
773         pend = buffer + SECTORSIZE;
774         for (p = buffer; p < pend && !*p; p++)
775                 ;
776
777         if (p < pend) {
778                 writeEUN = INFTL_findwriteunit(inftl, block);
779
780                 if (writeEUN == BLOCK_NIL) {
781                         printk(KERN_WARNING "inftl_writeblock(): cannot find "
782                                 "block to write to\n");
783                         /*
784                          * If we _still_ haven't got a block to use,
785                          * we're screwed.
786                          */
787                         return 1;
788                 }
789
790                 memset(&oob, 0xff, sizeof(struct inftl_oob));
791                 oob.b.Status = oob.b.Status1 = SECTOR_USED;
792
793                 nand_write_raw(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
794                                blockofs, SECTORSIZE, &retlen, (char *)buffer,
795                                (char *)&oob);
796                 /*
797                  * need to write SECTOR_USED flags since they are not written
798                  * in mtd_writeecc
799                  */
800         } else {
801                 INFTL_deleteblock(inftl, block);
802         }
803
804         return 0;
805 }
806
807 static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
808                            char *buffer)
809 {
810         struct INFTLrecord *inftl = (void *)mbd;
811         unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
812         unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
813         struct mtd_info *mtd = inftl->mbd.mtd;
814         unsigned int status;
815         int silly = MAX_LOOPS;
816         struct inftl_bci bci;
817         size_t retlen;
818
819         DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
820                 "buffer=%p)\n", inftl, block, buffer);
821
822         while (thisEUN < inftl->nb_blocks) {
823                 if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) +
824                                   blockofs, 8, &retlen, (char *)&bci) < 0)
825                         status = SECTOR_IGNORE;
826                 else
827                         status = bci.Status | bci.Status1;
828
829                 switch (status) {
830                 case SECTOR_DELETED:
831                         thisEUN = BLOCK_NIL;
832                         goto foundit;
833                 case SECTOR_USED:
834                         goto foundit;
835                 case SECTOR_FREE:
836                 case SECTOR_IGNORE:
837                         break;
838                 default:
839                         printk(KERN_WARNING "INFTL: unknown status for "
840                                 "block %ld in EUN %d: 0x%04x\n",
841                                 block, thisEUN, status);
842                         break;
843                 }
844
845                 if (!silly--) {
846                         printk(KERN_WARNING "INFTL: infinite loop in "
847                                 "Virtual Unit Chain 0x%lx\n",
848                                 block / (inftl->EraseSize / SECTORSIZE));
849                         return 1;
850                 }
851
852                 thisEUN = inftl->PUtable[thisEUN];
853         }
854
855 foundit:
856         if (thisEUN == BLOCK_NIL) {
857                 /* The requested block is not on the media, return all 0x00 */
858                 memset(buffer, 0, SECTORSIZE);
859         } else {
860                 size_t retlen;
861                 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
862                 if (mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer))
863                         return -EIO;
864         }
865         return 0;
866 }
867
868 static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
869 {
870         struct INFTLrecord *inftl = (void *)dev;
871
872         geo->heads = inftl->heads;
873         geo->sectors = inftl->sectors;
874         geo->cylinders = inftl->cylinders;
875
876         return 0;
877 }
878
879 static struct mtd_blktrans_ops inftl_tr = {
880         .name           = "inftl",
881         .major          = INFTL_MAJOR,
882         .part_bits      = INFTL_PARTN_BITS,
883         .getgeo         = inftl_getgeo,
884         .readsect       = inftl_readblock,
885         .writesect      = inftl_writeblock,
886         .add_mtd        = inftl_add_mtd,
887         .remove_dev     = inftl_remove_dev,
888         .owner          = THIS_MODULE,
889 };
890
891 static int __init init_inftl(void)
892 {
893         printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, "
894                 "inftlmount.c %s\n", inftlmountrev);
895
896         return register_mtd_blktrans(&inftl_tr);
897 }
898
899 static void __exit cleanup_inftl(void)
900 {
901         deregister_mtd_blktrans(&inftl_tr);
902 }
903
904 module_init(init_inftl);
905 module_exit(cleanup_inftl);
906
907 MODULE_LICENSE("GPL");
908 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
909 MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus");