linux/drivers/mtd/ftl.c
<<
>>
Prefs
   1/* This version ported to the Linux-MTD system by dwmw2@infradead.org
   2 *
   3 * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   4 * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
   5 *
   6 * Based on:
   7 */
   8/*======================================================================
   9
  10    A Flash Translation Layer memory card driver
  11
  12    This driver implements a disk-like block device driver with an
  13    apparent block size of 512 bytes for flash memory cards.
  14
  15    ftl_cs.c 1.62 2000/02/01 00:59:04
  16
  17    The contents of this file are subject to the Mozilla Public
  18    License Version 1.1 (the "License"); you may not use this file
  19    except in compliance with the License. You may obtain a copy of
  20    the License at http://www.mozilla.org/MPL/
  21
  22    Software distributed under the License is distributed on an "AS
  23    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  24    implied. See the License for the specific language governing
  25    rights and limitations under the License.
  26
  27    The initial developer of the original code is David A. Hinds
  28    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  29    are Copyright © 1999 David A. Hinds.  All Rights Reserved.
  30
  31    Alternatively, the contents of this file may be used under the
  32    terms of the GNU General Public License version 2 (the "GPL"), in
  33    which case the provisions of the GPL are applicable instead of the
  34    above.  If you wish to allow the use of your version of this file
  35    only under the terms of the GPL and not to allow others to use
  36    your version of this file under the MPL, indicate your decision
  37    by deleting the provisions above and replace them with the notice
  38    and other provisions required by the GPL.  If you do not delete
  39    the provisions above, a recipient may use your version of this
  40    file under either the MPL or the GPL.
  41
  42    LEGAL NOTE: The FTL format is patented by M-Systems.  They have
  43    granted a license for its use with PCMCIA devices:
  44
  45     "M-Systems grants a royalty-free, non-exclusive license under
  46      any presently existing M-Systems intellectual property rights
  47      necessary for the design and development of FTL-compatible
  48      drivers, file systems and utilities using the data formats with
  49      PCMCIA PC Cards as described in the PCMCIA Flash Translation
  50      Layer (FTL) Specification."
  51
  52    Use of the FTL format for non-PCMCIA applications may be an
  53    infringement of these patents.  For additional information,
  54    contact M-Systems directly. M-Systems since acquired by Sandisk. 
  55
  56======================================================================*/
  57#include <linux/mtd/blktrans.h>
  58#include <linux/module.h>
  59#include <linux/mtd/mtd.h>
  60/*#define PSYCHO_DEBUG */
  61
  62#include <linux/kernel.h>
  63#include <linux/ptrace.h>
  64#include <linux/slab.h>
  65#include <linux/string.h>
  66#include <linux/timer.h>
  67#include <linux/major.h>
  68#include <linux/fs.h>
  69#include <linux/init.h>
  70#include <linux/hdreg.h>
  71#include <linux/vmalloc.h>
  72#include <linux/blkpg.h>
  73#include <linux/uaccess.h>
  74
  75#include <linux/mtd/ftl.h>
  76
  77/*====================================================================*/
  78
  79/* Parameters that can be set with 'insmod' */
  80static int shuffle_freq = 50;
  81module_param(shuffle_freq, int, 0);
  82
  83/*====================================================================*/
  84
  85/* Major device # for FTL device */
  86#ifndef FTL_MAJOR
  87#define FTL_MAJOR       44
  88#endif
  89
  90
  91/*====================================================================*/
  92
  93/* Maximum number of separate memory devices we'll allow */
  94#define MAX_DEV         4
  95
  96/* Maximum number of regions per device */
  97#define MAX_REGION      4
  98
  99/* Maximum number of partitions in an FTL region */
 100#define PART_BITS       4
 101
 102/* Maximum number of outstanding erase requests per socket */
 103#define MAX_ERASE       8
 104
 105/* Sector size -- shouldn't need to change */
 106#define SECTOR_SIZE     512
 107
 108
 109/* Each memory region corresponds to a minor device */
 110typedef struct partition_t {
 111    struct mtd_blktrans_dev mbd;
 112    uint32_t            state;
 113    uint32_t            *VirtualBlockMap;
 114    uint32_t            FreeTotal;
 115    struct eun_info_t {
 116        uint32_t                Offset;
 117        uint32_t                EraseCount;
 118        uint32_t                Free;
 119        uint32_t                Deleted;
 120    } *EUNInfo;
 121    struct xfer_info_t {
 122        uint32_t                Offset;
 123        uint32_t                EraseCount;
 124        uint16_t                state;
 125    } *XferInfo;
 126    uint16_t            bam_index;
 127    uint32_t            *bam_cache;
 128    uint16_t            DataUnits;
 129    uint32_t            BlocksPerUnit;
 130    erase_unit_header_t header;
 131} partition_t;
 132
 133/* Partition state flags */
 134#define FTL_FORMATTED   0x01
 135
 136/* Transfer unit states */
 137#define XFER_UNKNOWN    0x00
 138#define XFER_ERASING    0x01
 139#define XFER_ERASED     0x02
 140#define XFER_PREPARED   0x03
 141#define XFER_FAILED     0x04
 142
 143/*======================================================================
 144
 145    Scan_header() checks to see if a memory region contains an FTL
 146    partition.  build_maps() reads all the erase unit headers, builds
 147    the erase unit map, and then builds the virtual page map.
 148
 149======================================================================*/
 150
 151static int scan_header(partition_t *part)
 152{
 153    erase_unit_header_t header;
 154    loff_t offset, max_offset;
 155    size_t ret;
 156    int err;
 157    part->header.FormattedSize = 0;
 158    max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
 159    /* Search first megabyte for a valid FTL header */
 160    for (offset = 0;
 161         (offset + sizeof(header)) < max_offset;
 162         offset += part->mbd.mtd->erasesize ? : 0x2000) {
 163
 164        err = mtd_read(part->mbd.mtd, offset, sizeof(header), &ret,
 165                       (unsigned char *)&header);
 166
 167        if (err)
 168            return err;
 169
 170        if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
 171    }
 172
 173    if (offset == max_offset) {
 174        printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
 175        return -ENOENT;
 176    }
 177    if (header.BlockSize != 9 ||
 178        (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
 179        (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
 180        printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
 181        return -1;
 182    }
 183    if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
 184        printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
 185               1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
 186        return -1;
 187    }
 188    part->header = header;
 189    return 0;
 190}
 191
 192static int build_maps(partition_t *part)
 193{
 194    erase_unit_header_t header;
 195    uint16_t xvalid, xtrans, i;
 196    unsigned blocks, j;
 197    int hdr_ok, ret = -1;
 198    ssize_t retval;
 199    loff_t offset;
 200
 201    /* Set up erase unit maps */
 202    part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
 203        part->header.NumTransferUnits;
 204    part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
 205                            GFP_KERNEL);
 206    if (!part->EUNInfo)
 207            goto out;
 208    for (i = 0; i < part->DataUnits; i++)
 209        part->EUNInfo[i].Offset = 0xffffffff;
 210    part->XferInfo =
 211        kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
 212                GFP_KERNEL);
 213    if (!part->XferInfo)
 214            goto out_EUNInfo;
 215
 216    xvalid = xtrans = 0;
 217    for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
 218        offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
 219                      << part->header.EraseUnitSize);
 220        ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval,
 221                       (unsigned char *)&header);
 222
 223        if (ret)
 224            goto out_XferInfo;
 225
 226        ret = -1;
 227        /* Is this a transfer partition? */
 228        hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
 229        if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
 230            (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
 231            part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
 232            part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
 233                le32_to_cpu(header.EraseCount);
 234            xvalid++;
 235        } else {
 236            if (xtrans == part->header.NumTransferUnits) {
 237                printk(KERN_NOTICE "ftl_cs: format error: too many "
 238                       "transfer units!\n");
 239                goto out_XferInfo;
 240            }
 241            if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
 242                part->XferInfo[xtrans].state = XFER_PREPARED;
 243                part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
 244            } else {
 245                part->XferInfo[xtrans].state = XFER_UNKNOWN;
 246                /* Pick anything reasonable for the erase count */
 247                part->XferInfo[xtrans].EraseCount =
 248                    le32_to_cpu(part->header.EraseCount);
 249            }
 250            part->XferInfo[xtrans].Offset = offset;
 251            xtrans++;
 252        }
 253    }
 254    /* Check for format trouble */
 255    header = part->header;
 256    if ((xtrans != header.NumTransferUnits) ||
 257        (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
 258        printk(KERN_NOTICE "ftl_cs: format error: erase units "
 259               "don't add up!\n");
 260        goto out_XferInfo;
 261    }
 262
 263    /* Set up virtual page map */
 264    blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
 265    part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t));
 266    if (!part->VirtualBlockMap)
 267            goto out_XferInfo;
 268
 269    memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
 270    part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
 271
 272    part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t),
 273                              GFP_KERNEL);
 274    if (!part->bam_cache)
 275            goto out_VirtualBlockMap;
 276
 277    part->bam_index = 0xffff;
 278    part->FreeTotal = 0;
 279
 280    for (i = 0; i < part->DataUnits; i++) {
 281        part->EUNInfo[i].Free = 0;
 282        part->EUNInfo[i].Deleted = 0;
 283        offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
 284
 285        ret = mtd_read(part->mbd.mtd, offset,
 286                       part->BlocksPerUnit * sizeof(uint32_t), &retval,
 287                       (unsigned char *)part->bam_cache);
 288
 289        if (ret)
 290                goto out_bam_cache;
 291
 292        for (j = 0; j < part->BlocksPerUnit; j++) {
 293            if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
 294                part->EUNInfo[i].Free++;
 295                part->FreeTotal++;
 296            } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
 297                     (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
 298                part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
 299                    (i << header.EraseUnitSize) + (j << header.BlockSize);
 300            else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
 301                part->EUNInfo[i].Deleted++;
 302        }
 303    }
 304
 305    ret = 0;
 306    goto out;
 307
 308out_bam_cache:
 309    kfree(part->bam_cache);
 310out_VirtualBlockMap:
 311    vfree(part->VirtualBlockMap);
 312out_XferInfo:
 313    kfree(part->XferInfo);
 314out_EUNInfo:
 315    kfree(part->EUNInfo);
 316out:
 317    return ret;
 318} /* build_maps */
 319
 320/*======================================================================
 321
 322    Erase_xfer() schedules an asynchronous erase operation for a
 323    transfer unit.
 324
 325======================================================================*/
 326
 327static int erase_xfer(partition_t *part,
 328                      uint16_t xfernum)
 329{
 330    int ret;
 331    struct xfer_info_t *xfer;
 332    struct erase_info *erase;
 333
 334    xfer = &part->XferInfo[xfernum];
 335    pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
 336    xfer->state = XFER_ERASING;
 337
 338    /* Is there a free erase slot? Always in MTD. */
 339
 340
 341    erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
 342    if (!erase)
 343            return -ENOMEM;
 344
 345    erase->addr = xfer->Offset;
 346    erase->len = 1 << part->header.EraseUnitSize;
 347
 348    ret = mtd_erase(part->mbd.mtd, erase);
 349    if (!ret) {
 350        xfer->state = XFER_ERASED;
 351        xfer->EraseCount++;
 352    } else {
 353        xfer->state = XFER_FAILED;
 354        pr_notice("ftl_cs: erase failed: err = %d\n", ret);
 355    }
 356
 357    kfree(erase);
 358
 359    return ret;
 360} /* erase_xfer */
 361
 362/*======================================================================
 363
 364    Prepare_xfer() takes a freshly erased transfer unit and gives
 365    it an appropriate header.
 366
 367======================================================================*/
 368
 369static int prepare_xfer(partition_t *part, int i)
 370{
 371    erase_unit_header_t header;
 372    struct xfer_info_t *xfer;
 373    int nbam, ret;
 374    uint32_t ctl;
 375    ssize_t retlen;
 376    loff_t offset;
 377
 378    xfer = &part->XferInfo[i];
 379    xfer->state = XFER_FAILED;
 380
 381    pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
 382
 383    /* Write the transfer unit header */
 384    header = part->header;
 385    header.LogicalEUN = cpu_to_le16(0xffff);
 386    header.EraseCount = cpu_to_le32(xfer->EraseCount);
 387
 388    ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen,
 389                    (u_char *)&header);
 390
 391    if (ret) {
 392        return ret;
 393    }
 394
 395    /* Write the BAM stub */
 396    nbam = DIV_ROUND_UP(part->BlocksPerUnit * sizeof(uint32_t) +
 397                        le32_to_cpu(part->header.BAMOffset), SECTOR_SIZE);
 398
 399    offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
 400    ctl = cpu_to_le32(BLOCK_CONTROL);
 401
 402    for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
 403
 404        ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
 405                        (u_char *)&ctl);
 406
 407        if (ret)
 408            return ret;
 409    }
 410    xfer->state = XFER_PREPARED;
 411    return 0;
 412
 413} /* prepare_xfer */
 414
 415/*======================================================================
 416
 417    Copy_erase_unit() takes a full erase block and a transfer unit,
 418    copies everything to the transfer unit, then swaps the block
 419    pointers.
 420
 421    All data blocks are copied to the corresponding blocks in the
 422    target unit, so the virtual block map does not need to be
 423    updated.
 424
 425======================================================================*/
 426
 427static int copy_erase_unit(partition_t *part, uint16_t srcunit,
 428                           uint16_t xferunit)
 429{
 430    u_char buf[SECTOR_SIZE];
 431    struct eun_info_t *eun;
 432    struct xfer_info_t *xfer;
 433    uint32_t src, dest, free, i;
 434    uint16_t unit;
 435    int ret;
 436    ssize_t retlen;
 437    loff_t offset;
 438    uint16_t srcunitswap = cpu_to_le16(srcunit);
 439
 440    eun = &part->EUNInfo[srcunit];
 441    xfer = &part->XferInfo[xferunit];
 442    pr_debug("ftl_cs: copying block 0x%x to 0x%x\n",
 443          eun->Offset, xfer->Offset);
 444
 445
 446    /* Read current BAM */
 447    if (part->bam_index != srcunit) {
 448
 449        offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
 450
 451        ret = mtd_read(part->mbd.mtd, offset,
 452                       part->BlocksPerUnit * sizeof(uint32_t), &retlen,
 453                       (u_char *)(part->bam_cache));
 454
 455        /* mark the cache bad, in case we get an error later */
 456        part->bam_index = 0xffff;
 457
 458        if (ret) {
 459            printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
 460            return ret;
 461        }
 462    }
 463
 464    /* Write the LogicalEUN for the transfer unit */
 465    xfer->state = XFER_UNKNOWN;
 466    offset = xfer->Offset + 20; /* Bad! */
 467    unit = cpu_to_le16(0x7fff);
 468
 469    ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen,
 470                    (u_char *)&unit);
 471
 472    if (ret) {
 473        printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
 474        return ret;
 475    }
 476
 477    /* Copy all data blocks from source unit to transfer unit */
 478    src = eun->Offset; dest = xfer->Offset;
 479
 480    free = 0;
 481    ret = 0;
 482    for (i = 0; i < part->BlocksPerUnit; i++) {
 483        switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
 484        case BLOCK_CONTROL:
 485            /* This gets updated later */
 486            break;
 487        case BLOCK_DATA:
 488        case BLOCK_REPLACEMENT:
 489            ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen,
 490                           (u_char *)buf);
 491            if (ret) {
 492                printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
 493                return ret;
 494            }
 495
 496
 497            ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen,
 498                            (u_char *)buf);
 499            if (ret)  {
 500                printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
 501                return ret;
 502            }
 503
 504            break;
 505        default:
 506            /* All other blocks must be free */
 507            part->bam_cache[i] = cpu_to_le32(0xffffffff);
 508            free++;
 509            break;
 510        }
 511        src += SECTOR_SIZE;
 512        dest += SECTOR_SIZE;
 513    }
 514
 515    /* Write the BAM to the transfer unit */
 516    ret = mtd_write(part->mbd.mtd,
 517                    xfer->Offset + le32_to_cpu(part->header.BAMOffset),
 518                    part->BlocksPerUnit * sizeof(int32_t),
 519                    &retlen,
 520                    (u_char *)part->bam_cache);
 521    if (ret) {
 522        printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
 523        return ret;
 524    }
 525
 526
 527    /* All clear? Then update the LogicalEUN again */
 528    ret = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
 529                    &retlen, (u_char *)&srcunitswap);
 530
 531    if (ret) {
 532        printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
 533        return ret;
 534    }
 535
 536
 537    /* Update the maps and usage stats*/
 538    swap(xfer->EraseCount, eun->EraseCount);
 539    swap(xfer->Offset, eun->Offset);
 540    part->FreeTotal -= eun->Free;
 541    part->FreeTotal += free;
 542    eun->Free = free;
 543    eun->Deleted = 0;
 544
 545    /* Now, the cache should be valid for the new block */
 546    part->bam_index = srcunit;
 547
 548    return 0;
 549} /* copy_erase_unit */
 550
 551/*======================================================================
 552
 553    reclaim_block() picks a full erase unit and a transfer unit and
 554    then calls copy_erase_unit() to copy one to the other.  Then, it
 555    schedules an erase on the expired block.
 556
 557    What's a good way to decide which transfer unit and which erase
 558    unit to use?  Beats me.  My way is to always pick the transfer
 559    unit with the fewest erases, and usually pick the data unit with
 560    the most deleted blocks.  But with a small probability, pick the
 561    oldest data unit instead.  This means that we generally postpone
 562    the next reclamation as long as possible, but shuffle static
 563    stuff around a bit for wear leveling.
 564
 565======================================================================*/
 566
 567static int reclaim_block(partition_t *part)
 568{
 569    uint16_t i, eun, xfer;
 570    uint32_t best;
 571    int queued, ret;
 572
 573    pr_debug("ftl_cs: reclaiming space...\n");
 574    pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits);
 575    /* Pick the least erased transfer unit */
 576    best = 0xffffffff; xfer = 0xffff;
 577    do {
 578        queued = 0;
 579        for (i = 0; i < part->header.NumTransferUnits; i++) {
 580            int n=0;
 581            if (part->XferInfo[i].state == XFER_UNKNOWN) {
 582                pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i);
 583                n=1;
 584                erase_xfer(part, i);
 585            }
 586            if (part->XferInfo[i].state == XFER_ERASING) {
 587                pr_debug("XferInfo[%d].state == XFER_ERASING\n",i);
 588                n=1;
 589                queued = 1;
 590            }
 591            else if (part->XferInfo[i].state == XFER_ERASED) {
 592                pr_debug("XferInfo[%d].state == XFER_ERASED\n",i);
 593                n=1;
 594                prepare_xfer(part, i);
 595            }
 596            if (part->XferInfo[i].state == XFER_PREPARED) {
 597                pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i);
 598                n=1;
 599                if (part->XferInfo[i].EraseCount <= best) {
 600                    best = part->XferInfo[i].EraseCount;
 601                    xfer = i;
 602                }
 603            }
 604                if (!n)
 605                    pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
 606
 607        }
 608        if (xfer == 0xffff) {
 609            if (queued) {
 610                pr_debug("ftl_cs: waiting for transfer "
 611                      "unit to be prepared...\n");
 612                mtd_sync(part->mbd.mtd);
 613            } else {
 614                static int ne = 0;
 615                if (++ne < 5)
 616                    printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
 617                           "suitable transfer units!\n");
 618                else
 619                    pr_debug("ftl_cs: reclaim failed: no "
 620                          "suitable transfer units!\n");
 621
 622                return -EIO;
 623            }
 624        }
 625    } while (xfer == 0xffff);
 626
 627    eun = 0;
 628    if ((jiffies % shuffle_freq) == 0) {
 629        pr_debug("ftl_cs: recycling freshest block...\n");
 630        best = 0xffffffff;
 631        for (i = 0; i < part->DataUnits; i++)
 632            if (part->EUNInfo[i].EraseCount <= best) {
 633                best = part->EUNInfo[i].EraseCount;
 634                eun = i;
 635            }
 636    } else {
 637        best = 0;
 638        for (i = 0; i < part->DataUnits; i++)
 639            if (part->EUNInfo[i].Deleted >= best) {
 640                best = part->EUNInfo[i].Deleted;
 641                eun = i;
 642            }
 643        if (best == 0) {
 644            static int ne = 0;
 645            if (++ne < 5)
 646                printk(KERN_NOTICE "ftl_cs: reclaim failed: "
 647                       "no free blocks!\n");
 648            else
 649                pr_debug("ftl_cs: reclaim failed: "
 650                       "no free blocks!\n");
 651
 652            return -EIO;
 653        }
 654    }
 655    ret = copy_erase_unit(part, eun, xfer);
 656    if (!ret)
 657        erase_xfer(part, xfer);
 658    else
 659        printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
 660    return ret;
 661} /* reclaim_block */
 662
 663/*======================================================================
 664
 665    Find_free() searches for a free block.  If necessary, it updates
 666    the BAM cache for the erase unit containing the free block.  It
 667    returns the block index -- the erase unit is just the currently
 668    cached unit.  If there are no free blocks, it returns 0 -- this
 669    is never a valid data block because it contains the header.
 670
 671======================================================================*/
 672
 673#ifdef PSYCHO_DEBUG
 674static void dump_lists(partition_t *part)
 675{
 676    int i;
 677    printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
 678    for (i = 0; i < part->DataUnits; i++)
 679        printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
 680               "%d deleted\n", i,
 681               part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
 682               part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
 683}
 684#endif
 685
 686static uint32_t find_free(partition_t *part)
 687{
 688    uint16_t stop, eun;
 689    uint32_t blk;
 690    size_t retlen;
 691    int ret;
 692
 693    /* Find an erase unit with some free space */
 694    stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
 695    eun = stop;
 696    do {
 697        if (part->EUNInfo[eun].Free != 0) break;
 698        /* Wrap around at end of table */
 699        if (++eun == part->DataUnits) eun = 0;
 700    } while (eun != stop);
 701
 702    if (part->EUNInfo[eun].Free == 0)
 703        return 0;
 704
 705    /* Is this unit's BAM cached? */
 706    if (eun != part->bam_index) {
 707        /* Invalidate cache */
 708        part->bam_index = 0xffff;
 709
 710        ret = mtd_read(part->mbd.mtd,
 711                       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
 712                       part->BlocksPerUnit * sizeof(uint32_t),
 713                       &retlen,
 714                       (u_char *)(part->bam_cache));
 715
 716        if (ret) {
 717            printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
 718            return 0;
 719        }
 720        part->bam_index = eun;
 721    }
 722
 723    /* Find a free block */
 724    for (blk = 0; blk < part->BlocksPerUnit; blk++)
 725        if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
 726    if (blk == part->BlocksPerUnit) {
 727#ifdef PSYCHO_DEBUG
 728        static int ne = 0;
 729        if (++ne == 1)
 730            dump_lists(part);
 731#endif
 732        printk(KERN_NOTICE "ftl_cs: bad free list!\n");
 733        return 0;
 734    }
 735    pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun);
 736    return blk;
 737
 738} /* find_free */
 739
 740
 741/*======================================================================
 742
 743    Read a series of sectors from an FTL partition.
 744
 745======================================================================*/
 746
 747static int ftl_read(partition_t *part, caddr_t buffer,
 748                    u_long sector, u_long nblocks)
 749{
 750    uint32_t log_addr, bsize;
 751    u_long i;
 752    int ret;
 753    size_t offset, retlen;
 754
 755    pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
 756          part, sector, nblocks);
 757    if (!(part->state & FTL_FORMATTED)) {
 758        printk(KERN_NOTICE "ftl_cs: bad partition\n");
 759        return -EIO;
 760    }
 761    bsize = 1 << part->header.EraseUnitSize;
 762
 763    for (i = 0; i < nblocks; i++) {
 764        if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
 765            printk(KERN_NOTICE "ftl_cs: bad read offset\n");
 766            return -EIO;
 767        }
 768        log_addr = part->VirtualBlockMap[sector+i];
 769        if (log_addr == 0xffffffff)
 770            memset(buffer, 0, SECTOR_SIZE);
 771        else {
 772            offset = (part->EUNInfo[log_addr / bsize].Offset
 773                          + (log_addr % bsize));
 774            ret = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
 775                           (u_char *)buffer);
 776
 777            if (ret) {
 778                printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
 779                return ret;
 780            }
 781        }
 782        buffer += SECTOR_SIZE;
 783    }
 784    return 0;
 785} /* ftl_read */
 786
 787/*======================================================================
 788
 789    Write a series of sectors to an FTL partition
 790
 791======================================================================*/
 792
 793static int set_bam_entry(partition_t *part, uint32_t log_addr,
 794                         uint32_t virt_addr)
 795{
 796    uint32_t bsize, blk, le_virt_addr;
 797#ifdef PSYCHO_DEBUG
 798    uint32_t old_addr;
 799#endif
 800    uint16_t eun;
 801    int ret;
 802    size_t retlen, offset;
 803
 804    pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
 805          part, log_addr, virt_addr);
 806    bsize = 1 << part->header.EraseUnitSize;
 807    eun = log_addr / bsize;
 808    blk = (log_addr % bsize) / SECTOR_SIZE;
 809    offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
 810                  le32_to_cpu(part->header.BAMOffset));
 811
 812#ifdef PSYCHO_DEBUG
 813    ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
 814                   (u_char *)&old_addr);
 815    if (ret) {
 816        printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
 817        return ret;
 818    }
 819    old_addr = le32_to_cpu(old_addr);
 820
 821    if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
 822        ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
 823        (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
 824        static int ne = 0;
 825        if (++ne < 5) {
 826            printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
 827            printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"
 828                   ", new = 0x%x\n", log_addr, old_addr, virt_addr);
 829        }
 830        return -EIO;
 831    }
 832#endif
 833    le_virt_addr = cpu_to_le32(virt_addr);
 834    if (part->bam_index == eun) {
 835#ifdef PSYCHO_DEBUG
 836        if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
 837            static int ne = 0;
 838            if (++ne < 5) {
 839                printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
 840                       "inconsistency!\n");
 841                printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"
 842                       " = 0x%x\n",
 843                       le32_to_cpu(part->bam_cache[blk]), old_addr);
 844            }
 845            return -EIO;
 846        }
 847#endif
 848        part->bam_cache[blk] = le_virt_addr;
 849    }
 850    ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
 851                    (u_char *)&le_virt_addr);
 852
 853    if (ret) {
 854        printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
 855        printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",
 856               log_addr, virt_addr);
 857    }
 858    return ret;
 859} /* set_bam_entry */
 860
 861static int ftl_write(partition_t *part, caddr_t buffer,
 862                     u_long sector, u_long nblocks)
 863{
 864    uint32_t bsize, log_addr, virt_addr, old_addr, blk;
 865    u_long i;
 866    int ret;
 867    size_t retlen, offset;
 868
 869    pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
 870          part, sector, nblocks);
 871    if (!(part->state & FTL_FORMATTED)) {
 872        printk(KERN_NOTICE "ftl_cs: bad partition\n");
 873        return -EIO;
 874    }
 875    /* See if we need to reclaim space, before we start */
 876    while (part->FreeTotal < nblocks) {
 877        ret = reclaim_block(part);
 878        if (ret)
 879            return ret;
 880    }
 881
 882    bsize = 1 << part->header.EraseUnitSize;
 883
 884    virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
 885    for (i = 0; i < nblocks; i++) {
 886        if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
 887            printk(KERN_NOTICE "ftl_cs: bad write offset\n");
 888            return -EIO;
 889        }
 890
 891        /* Grab a free block */
 892        blk = find_free(part);
 893        if (blk == 0) {
 894            static int ne = 0;
 895            if (++ne < 5)
 896                printk(KERN_NOTICE "ftl_cs: internal error: "
 897                       "no free blocks!\n");
 898            return -ENOSPC;
 899        }
 900
 901        /* Tag the BAM entry, and write the new block */
 902        log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
 903        part->EUNInfo[part->bam_index].Free--;
 904        part->FreeTotal--;
 905        if (set_bam_entry(part, log_addr, 0xfffffffe))
 906            return -EIO;
 907        part->EUNInfo[part->bam_index].Deleted++;
 908        offset = (part->EUNInfo[part->bam_index].Offset +
 909                      blk * SECTOR_SIZE);
 910        ret = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer);
 911
 912        if (ret) {
 913            printk(KERN_NOTICE "ftl_cs: block write failed!\n");
 914            printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
 915                   " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
 916                   offset);
 917            return -EIO;
 918        }
 919
 920        /* Only delete the old entry when the new entry is ready */
 921        old_addr = part->VirtualBlockMap[sector+i];
 922        if (old_addr != 0xffffffff) {
 923            part->VirtualBlockMap[sector+i] = 0xffffffff;
 924            part->EUNInfo[old_addr/bsize].Deleted++;
 925            if (set_bam_entry(part, old_addr, 0))
 926                return -EIO;
 927        }
 928
 929        /* Finally, set up the new pointers */
 930        if (set_bam_entry(part, log_addr, virt_addr))
 931            return -EIO;
 932        part->VirtualBlockMap[sector+i] = log_addr;
 933        part->EUNInfo[part->bam_index].Deleted--;
 934
 935        buffer += SECTOR_SIZE;
 936        virt_addr += SECTOR_SIZE;
 937    }
 938    return 0;
 939} /* ftl_write */
 940
 941static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
 942{
 943        partition_t *part = (void *)dev;
 944        u_long sect;
 945
 946        /* Sort of arbitrary: round size down to 4KiB boundary */
 947        sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
 948
 949        geo->heads = 1;
 950        geo->sectors = 8;
 951        geo->cylinders = sect >> 3;
 952
 953        return 0;
 954}
 955
 956static int ftl_readsect(struct mtd_blktrans_dev *dev,
 957                              unsigned long block, char *buf)
 958{
 959        return ftl_read((void *)dev, buf, block, 1);
 960}
 961
 962static int ftl_writesect(struct mtd_blktrans_dev *dev,
 963                              unsigned long block, char *buf)
 964{
 965        return ftl_write((void *)dev, buf, block, 1);
 966}
 967
 968static int ftl_discardsect(struct mtd_blktrans_dev *dev,
 969                           unsigned long sector, unsigned nr_sects)
 970{
 971        partition_t *part = (void *)dev;
 972        uint32_t bsize = 1 << part->header.EraseUnitSize;
 973
 974        pr_debug("FTL erase sector %ld for %d sectors\n",
 975              sector, nr_sects);
 976
 977        while (nr_sects) {
 978                uint32_t old_addr = part->VirtualBlockMap[sector];
 979                if (old_addr != 0xffffffff) {
 980                        part->VirtualBlockMap[sector] = 0xffffffff;
 981                        part->EUNInfo[old_addr/bsize].Deleted++;
 982                        if (set_bam_entry(part, old_addr, 0))
 983                                return -EIO;
 984                }
 985                nr_sects--;
 986                sector++;
 987        }
 988
 989        return 0;
 990}
 991/*====================================================================*/
 992
 993static void ftl_freepart(partition_t *part)
 994{
 995        vfree(part->VirtualBlockMap);
 996        part->VirtualBlockMap = NULL;
 997        kfree(part->EUNInfo);
 998        part->EUNInfo = NULL;
 999        kfree(part->XferInfo);
1000        part->XferInfo = NULL;
1001        kfree(part->bam_cache);
1002        part->bam_cache = NULL;
1003} /* ftl_freepart */
1004
1005static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1006{
1007        partition_t *partition;
1008
1009        partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1010
1011        if (!partition) {
1012                printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1013                       mtd->name);
1014                return;
1015        }
1016
1017        partition->mbd.mtd = mtd;
1018
1019        if ((scan_header(partition) == 0) &&
1020            (build_maps(partition) == 0)) {
1021
1022                partition->state = FTL_FORMATTED;
1023#ifdef PCMCIA_DEBUG
1024                printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1025                       le32_to_cpu(partition->header.FormattedSize) >> 10);
1026#endif
1027                partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1028
1029                partition->mbd.tr = tr;
1030                partition->mbd.devnum = -1;
1031                if (!add_mtd_blktrans_dev((void *)partition))
1032                        return;
1033        }
1034
1035        kfree(partition);
1036}
1037
1038static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1039{
1040        del_mtd_blktrans_dev(dev);
1041        ftl_freepart((partition_t *)dev);
1042}
1043
1044static struct mtd_blktrans_ops ftl_tr = {
1045        .name           = "ftl",
1046        .major          = FTL_MAJOR,
1047        .part_bits      = PART_BITS,
1048        .blksize        = SECTOR_SIZE,
1049        .readsect       = ftl_readsect,
1050        .writesect      = ftl_writesect,
1051        .discard        = ftl_discardsect,
1052        .getgeo         = ftl_getgeo,
1053        .add_mtd        = ftl_add_mtd,
1054        .remove_dev     = ftl_remove_dev,
1055        .owner          = THIS_MODULE,
1056};
1057
1058static int __init init_ftl(void)
1059{
1060        return register_mtd_blktrans(&ftl_tr);
1061}
1062
1063static void __exit cleanup_ftl(void)
1064{
1065        deregister_mtd_blktrans(&ftl_tr);
1066}
1067
1068module_init(init_ftl);
1069module_exit(cleanup_ftl);
1070
1071
1072MODULE_LICENSE("Dual MPL/GPL");
1073MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1074MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
1075