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