linux-old/drivers/mtd/ftl.c
<<
>>
Prefs
   1/* This version ported to the Linux-MTD system by dwmw2@infradead.org
   2 * $Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $
   3 *
   4 * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   5 * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
   6 *
   7 * Based on:
   8 */
   9/*======================================================================
  10
  11    A Flash Translation Layer memory card driver
  12
  13    This driver implements a disk-like block device driver with an
  14    apparent block size of 512 bytes for flash memory cards.
  15
  16    ftl_cs.c 1.62 2000/02/01 00:59:04
  17
  18    The contents of this file are subject to the Mozilla Public
  19    License Version 1.1 (the "License"); you may not use this file
  20    except in compliance with the License. You may obtain a copy of
  21    the License at http://www.mozilla.org/MPL/
  22
  23    Software distributed under the License is distributed on an "AS
  24    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  25    implied. See the License for the specific language governing
  26    rights and limitations under the License.
  27
  28    The initial developer of the original code is David A. Hinds
  29    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  30    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  31
  32    Alternatively, the contents of this file may be used under the
  33    terms of the GNU General Public License version 2 (the "GPL"), in
  34    which case the provisions of the GPL are applicable instead of the
  35    above.  If you wish to allow the use of your version of this file
  36    only under the terms of the GPL and not to allow others to use
  37    your version of this file under the MPL, indicate your decision
  38    by deleting the provisions above and replace them with the notice
  39    and other provisions required by the GPL.  If you do not delete
  40    the provisions above, a recipient may use your version of this
  41    file under either the MPL or the GPL.
  42
  43    LEGAL NOTE: The FTL format is patented by M-Systems.  They have
  44    granted a license for its use with PCMCIA devices:
  45
  46     "M-Systems grants a royalty-free, non-exclusive license under
  47      any presently existing M-Systems intellectual property rights
  48      necessary for the design and development of FTL-compatible
  49      drivers, file systems and utilities using the data formats with
  50      PCMCIA PC Cards as described in the PCMCIA Flash Translation
  51      Layer (FTL) Specification."
  52
  53    Use of the FTL format for non-PCMCIA applications may be an
  54    infringement of these patents.  For additional information,
  55    contact M-Systems (http://www.m-sys.com) directly.
  56      
  57======================================================================*/
  58#include <linux/module.h>
  59#include <linux/mtd/compatmac.h>
  60#include <linux/mtd/mtd.h>
  61/*#define PSYCHO_DEBUG */
  62
  63#include <linux/kernel.h>
  64#include <linux/sched.h>
  65#include <linux/ptrace.h>
  66#include <linux/slab.h>
  67#include <linux/string.h>
  68#include <linux/timer.h>
  69#include <linux/major.h>
  70#include <linux/fs.h>
  71#include <linux/ioctl.h>
  72#include <linux/hdreg.h>
  73
  74#if (LINUX_VERSION_CODE >= 0x20100)
  75#include <linux/vmalloc.h>
  76#endif
  77#if (LINUX_VERSION_CODE >= 0x20303)
  78#include <linux/blkpg.h>
  79#endif
  80
  81#include <linux/mtd/ftl.h>
  82/*====================================================================*/
  83/* Stuff which really ought to be in compatmac.h */
  84
  85#if (LINUX_VERSION_CODE < 0x20328)
  86#define register_disk(dev, drive, minors, ops, size) \
  87    do { (dev)->part[(drive)*(minors)].nr_sects = size; \
  88        if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
  89        resetup_one_dev(dev, drive); } while (0)
  90#endif
  91
  92#if (LINUX_VERSION_CODE < 0x20320)
  93#define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn
  94#define blk_init_queue(q, req)  q = (req)
  95#define blk_cleanup_queue(q)    q = NULL
  96#define request_arg_t           void
  97#else
  98#define request_arg_t           request_queue_t *q
  99#endif
 100
 101#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
 102#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
 103#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
 104#else
 105#define BLK_INC_USE_COUNT do {} while(0)
 106#define BLK_DEC_USE_COUNT do {} while(0)
 107#endif
 108
 109/*====================================================================*/
 110
 111/* Parameters that can be set with 'insmod' */
 112static int shuffle_freq = 50;
 113MODULE_PARM(shuffle_freq, "i");
 114
 115/*====================================================================*/
 116
 117/* Major device # for FTL device */
 118#ifndef FTL_MAJOR
 119#define FTL_MAJOR       44
 120#endif
 121
 122/* Funky stuff for setting up a block device */
 123#define MAJOR_NR                FTL_MAJOR
 124#define DEVICE_NAME             "ftl"
 125#define DEVICE_REQUEST          do_ftl_request
 126#define DEVICE_ON(device)
 127#define DEVICE_OFF(device)
 128
 129#define DEVICE_NR(minor)        ((minor)>>5)
 130#define REGION_NR(minor)        (((minor)>>3)&3)
 131#define PART_NR(minor)          ((minor)&7)
 132#define MINOR_NR(dev,reg,part)  (((dev)<<5)+((reg)<<3)+(part))
 133
 134#include <linux/blk.h>
 135
 136/*====================================================================*/
 137
 138/* Maximum number of separate memory devices we'll allow */
 139#define MAX_DEV         4
 140
 141/* Maximum number of regions per device */
 142#define MAX_REGION      4
 143
 144/* Maximum number of partitions in an FTL region */
 145#define PART_BITS       3
 146#define MAX_PART        8
 147
 148/* Maximum number of outstanding erase requests per socket */
 149#define MAX_ERASE       8
 150
 151/* Sector size -- shouldn't need to change */
 152#define SECTOR_SIZE     512
 153
 154
 155/* Each memory region corresponds to a minor device */
 156typedef struct partition_t {
 157    struct mtd_info     *mtd;
 158    u_int32_t           state;
 159    u_int32_t           *VirtualBlockMap;
 160    u_int32_t           *VirtualPageMap;
 161    u_int32_t           FreeTotal;
 162    struct eun_info_t {
 163        u_int32_t               Offset;
 164        u_int32_t               EraseCount;
 165        u_int32_t               Free;
 166        u_int32_t               Deleted;
 167    } *EUNInfo;
 168    struct xfer_info_t {
 169        u_int32_t               Offset;
 170        u_int32_t               EraseCount;
 171        u_int16_t               state;
 172    } *XferInfo;
 173    u_int16_t           bam_index;
 174    u_int32_t           *bam_cache;
 175    u_int16_t           DataUnits;
 176    u_int32_t           BlocksPerUnit;
 177    erase_unit_header_t header;
 178#if 0
 179    region_info_t       region;
 180    memory_handle_t     handle;
 181#endif
 182    atomic_t            open;
 183} partition_t;
 184
 185partition_t *myparts[MAX_MTD_DEVICES];
 186
 187static void ftl_notify_add(struct mtd_info *mtd);
 188static void ftl_notify_remove(struct mtd_info *mtd);
 189
 190void ftl_freepart(partition_t *part);
 191
 192static struct mtd_notifier ftl_notifier = {
 193        add:    ftl_notify_add,
 194        remove: ftl_notify_remove,
 195};
 196
 197/* Partition state flags */
 198#define FTL_FORMATTED   0x01
 199
 200/* Transfer unit states */
 201#define XFER_UNKNOWN    0x00
 202#define XFER_ERASING    0x01
 203#define XFER_ERASED     0x02
 204#define XFER_PREPARED   0x03
 205#define XFER_FAILED     0x04
 206
 207static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
 208static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
 209static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
 210
 211static struct gendisk ftl_gendisk = {
 212    major:              FTL_MAJOR,
 213    major_name:         "ftl",
 214    minor_shift:        PART_BITS,
 215    max_p:              MAX_PART,
 216#if (LINUX_VERSION_CODE < 0x20328)
 217    max_nr:             MAX_DEV*MAX_PART,
 218#endif
 219    part:               ftl_hd,
 220    sizes:              ftl_sizes,
 221};
 222
 223/*====================================================================*/
 224
 225static int ftl_ioctl(struct inode *inode, struct file *file,
 226                     u_int cmd, u_long arg);
 227static int ftl_open(struct inode *inode, struct file *file);
 228static release_t ftl_close(struct inode *inode, struct file *file);
 229static int ftl_reread_partitions(int minor);
 230
 231static void ftl_erase_callback(struct erase_info *done);
 232
 233#if LINUX_VERSION_CODE < 0x20326
 234static struct file_operations ftl_blk_fops = {
 235    open:       ftl_open,
 236    release:    ftl_close,
 237    ioctl:      ftl_ioctl,
 238    read:       block_read,
 239    write:      block_write,
 240    fsync:      block_fsync
 241};
 242#else
 243static struct block_device_operations ftl_blk_fops = {
 244#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
 245    owner:      THIS_MODULE,
 246#endif
 247    open:       ftl_open,
 248    release:    ftl_close,
 249    ioctl:      ftl_ioctl,
 250};
 251#endif
 252
 253/*======================================================================
 254
 255    Scan_header() checks to see if a memory region contains an FTL
 256    partition.  build_maps() reads all the erase unit headers, builds
 257    the erase unit map, and then builds the virtual page map.
 258    
 259======================================================================*/
 260
 261static int scan_header(partition_t *part)
 262{
 263    erase_unit_header_t header;
 264    loff_t offset, max_offset;
 265    int ret;
 266    part->header.FormattedSize = 0;
 267    max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size;
 268    /* Search first megabyte for a valid FTL header */
 269    for (offset = 0;
 270         (offset + sizeof(header)) < max_offset;
 271         offset += part->mtd->erasesize ? : 0x2000) {
 272
 273        ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, 
 274                              (unsigned char *)&header);
 275        
 276        if (ret) 
 277            return ret;
 278
 279        if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
 280    }
 281
 282    if (offset == max_offset) {
 283        printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
 284        return -ENOENT;
 285    }
 286    if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
 287        (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
 288        (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
 289        printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
 290        return -1;
 291    }
 292    if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
 293        printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
 294               1 << header.EraseUnitSize,part->mtd->erasesize);
 295        return -1;
 296    }
 297    part->header = header;
 298    return 0;
 299}
 300
 301static int build_maps(partition_t *part)
 302{
 303    erase_unit_header_t header;
 304    u_int16_t xvalid, xtrans, i;
 305    u_int blocks, j;
 306    int hdr_ok, ret = -1;
 307    ssize_t retval;
 308    loff_t offset;
 309
 310    /* Set up erase unit maps */
 311    part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
 312        part->header.NumTransferUnits;
 313    part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
 314                            GFP_KERNEL);
 315    if (!part->EUNInfo)
 316            goto out;
 317    for (i = 0; i < part->DataUnits; i++)
 318        part->EUNInfo[i].Offset = 0xffffffff;
 319    part->XferInfo =
 320        kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
 321                GFP_KERNEL);
 322    if (!part->XferInfo)
 323            goto out_EUNInfo;
 324
 325    xvalid = xtrans = 0;
 326    for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
 327        offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
 328                      << part->header.EraseUnitSize);
 329        ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval, 
 330                              (unsigned char *)&header);
 331        
 332        if (ret) 
 333            goto out_XferInfo;
 334
 335        ret = -1;
 336        /* Is this a transfer partition? */
 337        hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
 338        if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
 339            (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
 340            part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
 341            part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
 342                le32_to_cpu(header.EraseCount);
 343            xvalid++;
 344        } else {
 345            if (xtrans == part->header.NumTransferUnits) {
 346                printk(KERN_NOTICE "ftl_cs: format error: too many "
 347                       "transfer units!\n");
 348                goto out_XferInfo;
 349            }
 350            if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
 351                part->XferInfo[xtrans].state = XFER_PREPARED;
 352                part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
 353            } else {
 354                part->XferInfo[xtrans].state = XFER_UNKNOWN;
 355                /* Pick anything reasonable for the erase count */
 356                part->XferInfo[xtrans].EraseCount =
 357                    le32_to_cpu(part->header.EraseCount);
 358            }
 359            part->XferInfo[xtrans].Offset = offset;
 360            xtrans++;
 361        }
 362    }
 363    /* Check for format trouble */
 364    header = part->header;
 365    if ((xtrans != header.NumTransferUnits) ||
 366        (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
 367        printk(KERN_NOTICE "ftl_cs: format error: erase units "
 368               "don't add up!\n");
 369        goto out_XferInfo;
 370    }
 371    
 372    /* Set up virtual page map */
 373    blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
 374    part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
 375    if (!part->VirtualBlockMap)
 376            goto out_XferInfo;
 377
 378    memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
 379    part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
 380
 381    part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
 382                              GFP_KERNEL);
 383    if (!part->bam_cache)
 384            goto out_VirtualBlockMap;
 385
 386    part->bam_index = 0xffff;
 387    part->FreeTotal = 0;
 388
 389    for (i = 0; i < part->DataUnits; i++) {
 390        part->EUNInfo[i].Free = 0;
 391        part->EUNInfo[i].Deleted = 0;
 392        offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
 393        
 394        ret = part->mtd->read(part->mtd, offset,  
 395                              part->BlocksPerUnit * sizeof(u_int32_t), &retval, 
 396                              (unsigned char *)part->bam_cache);
 397        
 398        if (ret) 
 399                goto out_bam_cache;
 400
 401        for (j = 0; j < part->BlocksPerUnit; j++) {
 402            if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
 403                part->EUNInfo[i].Free++;
 404                part->FreeTotal++;
 405            } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
 406                     (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
 407                part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
 408                    (i << header.EraseUnitSize) + (j << header.BlockSize);
 409            else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
 410                part->EUNInfo[i].Deleted++;
 411        }
 412    }
 413    
 414    ret = 0;
 415    goto out;
 416
 417out_bam_cache:
 418    kfree(part->bam_cache);
 419out_VirtualBlockMap:
 420    vfree(part->VirtualBlockMap);
 421out_XferInfo:
 422    kfree(part->XferInfo);
 423out_EUNInfo:
 424    kfree(part->EUNInfo);
 425out:
 426    return ret;
 427} /* build_maps */
 428
 429/*======================================================================
 430
 431    Erase_xfer() schedules an asynchronous erase operation for a
 432    transfer unit.
 433    
 434======================================================================*/
 435
 436static int erase_xfer(partition_t *part,
 437                      u_int16_t xfernum)
 438{
 439    int ret;
 440    struct xfer_info_t *xfer;
 441    struct erase_info *erase;
 442
 443    xfer = &part->XferInfo[xfernum];
 444    DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
 445    xfer->state = XFER_ERASING;
 446
 447    /* Is there a free erase slot? Always in MTD. */
 448    
 449    
 450    erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
 451    if (!erase) 
 452            return -ENOMEM;
 453
 454    erase->callback = ftl_erase_callback;
 455    erase->addr = xfer->Offset;
 456    erase->len = 1 << part->header.EraseUnitSize;
 457    erase->priv = (u_long)part;
 458    
 459    ret = part->mtd->erase(part->mtd, erase);
 460
 461    if (!ret)
 462            xfer->EraseCount++;
 463    else
 464            kfree(erase);
 465
 466    return ret;
 467} /* erase_xfer */
 468
 469/*======================================================================
 470
 471    Prepare_xfer() takes a freshly erased transfer unit and gives
 472    it an appropriate header.
 473    
 474======================================================================*/
 475
 476static void ftl_erase_callback(struct erase_info *erase)
 477{
 478    partition_t *part;
 479    struct xfer_info_t *xfer;
 480    int i;
 481    
 482    /* Look up the transfer unit */
 483    part = (partition_t *)(erase->priv);
 484
 485    for (i = 0; i < part->header.NumTransferUnits; i++)
 486        if (part->XferInfo[i].Offset == erase->addr) break;
 487
 488    if (i == part->header.NumTransferUnits) {
 489        printk(KERN_NOTICE "ftl_cs: internal error: "
 490               "erase lookup failed!\n");
 491        return;
 492    }
 493
 494    xfer = &part->XferInfo[i];
 495    if (erase->state == MTD_ERASE_DONE)
 496        xfer->state = XFER_ERASED;
 497    else {
 498        xfer->state = XFER_FAILED;
 499        printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
 500               erase->state);
 501    }
 502
 503    kfree(erase);
 504
 505} /* ftl_erase_callback */
 506
 507static int prepare_xfer(partition_t *part, int i)
 508{
 509    erase_unit_header_t header;
 510    struct xfer_info_t *xfer;
 511    int nbam, ret;
 512    u_int32_t ctl;
 513    ssize_t retlen;
 514    loff_t offset;
 515
 516    xfer = &part->XferInfo[i];
 517    xfer->state = XFER_FAILED;
 518    
 519    DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
 520
 521    /* Write the transfer unit header */
 522    header = part->header;
 523    header.LogicalEUN = cpu_to_le16(0xffff);
 524    header.EraseCount = cpu_to_le32(xfer->EraseCount);
 525
 526    ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
 527                           &retlen, (u_char *)&header);
 528
 529    if (ret) {
 530        return ret;
 531    }
 532
 533    /* Write the BAM stub */
 534    nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
 535            le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
 536
 537    offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
 538    ctl = cpu_to_le32(BLOCK_CONTROL);
 539
 540    for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
 541
 542        ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), 
 543                               &retlen, (u_char *)&ctl);
 544
 545        if (ret)
 546            return ret;
 547    }
 548    xfer->state = XFER_PREPARED;
 549    return 0;
 550    
 551} /* prepare_xfer */
 552
 553/*======================================================================
 554
 555    Copy_erase_unit() takes a full erase block and a transfer unit,
 556    copies everything to the transfer unit, then swaps the block
 557    pointers.
 558
 559    All data blocks are copied to the corresponding blocks in the
 560    target unit, so the virtual block map does not need to be
 561    updated.
 562    
 563======================================================================*/
 564
 565static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
 566                           u_int16_t xferunit)
 567{
 568    u_char buf[SECTOR_SIZE];
 569    struct eun_info_t *eun;
 570    struct xfer_info_t *xfer;
 571    u_int32_t src, dest, free, i;
 572    u_int16_t unit;
 573    int ret;
 574    ssize_t retlen;
 575    loff_t offset;
 576    u_int16_t srcunitswap = cpu_to_le16(srcunit);
 577
 578    eun = &part->EUNInfo[srcunit];
 579    xfer = &part->XferInfo[xferunit];
 580    DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
 581          eun->Offset, xfer->Offset);
 582        
 583    
 584    /* Read current BAM */
 585    if (part->bam_index != srcunit) {
 586
 587        offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
 588
 589        ret = part->mtd->read(part->mtd, offset, 
 590                              part->BlocksPerUnit * sizeof(u_int32_t),
 591                              &retlen, (u_char *) (part->bam_cache));
 592
 593        /* mark the cache bad, in case we get an error later */
 594        part->bam_index = 0xffff;
 595
 596        if (ret) {
 597            printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");                
 598            return ret;
 599        }
 600    }
 601    
 602    /* Write the LogicalEUN for the transfer unit */
 603    xfer->state = XFER_UNKNOWN;
 604    offset = xfer->Offset + 20; /* Bad! */
 605    unit = cpu_to_le16(0x7fff);
 606
 607    ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
 608                           &retlen, (u_char *) &unit);
 609    
 610    if (ret) {
 611        printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
 612        return ret;
 613    }
 614    
 615    /* Copy all data blocks from source unit to transfer unit */
 616    src = eun->Offset; dest = xfer->Offset;
 617
 618    free = 0;
 619    ret = 0;
 620    for (i = 0; i < part->BlocksPerUnit; i++) {
 621        switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
 622        case BLOCK_CONTROL:
 623            /* This gets updated later */
 624            break;
 625        case BLOCK_DATA:
 626        case BLOCK_REPLACEMENT:
 627            ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
 628                        &retlen, (u_char *) buf);
 629            if (ret) {
 630                printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
 631                return ret;
 632            }
 633
 634
 635            ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
 636                        &retlen, (u_char *) buf);
 637            if (ret)  {
 638                printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
 639                return ret;
 640            }
 641
 642            break;
 643        default:
 644            /* All other blocks must be free */
 645            part->bam_cache[i] = cpu_to_le32(0xffffffff);
 646            free++;
 647            break;
 648        }
 649        src += SECTOR_SIZE;
 650        dest += SECTOR_SIZE;
 651    }
 652
 653    /* Write the BAM to the transfer unit */
 654    ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), 
 655                    part->BlocksPerUnit * sizeof(int32_t), &retlen, 
 656                    (u_char *)part->bam_cache);
 657    if (ret) {
 658        printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
 659        return ret;
 660    }
 661
 662    
 663    /* All clear? Then update the LogicalEUN again */
 664    ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
 665                           &retlen, (u_char *)&srcunitswap);
 666
 667    if (ret) {
 668        printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
 669        return ret;
 670    }    
 671    
 672    
 673    /* Update the maps and usage stats*/
 674    i = xfer->EraseCount;
 675    xfer->EraseCount = eun->EraseCount;
 676    eun->EraseCount = i;
 677    i = xfer->Offset;
 678    xfer->Offset = eun->Offset;
 679    eun->Offset = i;
 680    part->FreeTotal -= eun->Free;
 681    part->FreeTotal += free;
 682    eun->Free = free;
 683    eun->Deleted = 0;
 684    
 685    /* Now, the cache should be valid for the new block */
 686    part->bam_index = srcunit;
 687    
 688    return 0;
 689} /* copy_erase_unit */
 690
 691/*======================================================================
 692
 693    reclaim_block() picks a full erase unit and a transfer unit and
 694    then calls copy_erase_unit() to copy one to the other.  Then, it
 695    schedules an erase on the expired block.
 696
 697    What's a good way to decide which transfer unit and which erase
 698    unit to use?  Beats me.  My way is to always pick the transfer
 699    unit with the fewest erases, and usually pick the data unit with
 700    the most deleted blocks.  But with a small probability, pick the
 701    oldest data unit instead.  This means that we generally postpone
 702    the next reclaimation as long as possible, but shuffle static
 703    stuff around a bit for wear leveling.
 704    
 705======================================================================*/
 706
 707static int reclaim_block(partition_t *part)
 708{
 709    u_int16_t i, eun, xfer;
 710    u_int32_t best;
 711    int queued, ret;
 712
 713    DEBUG(0, "ftl_cs: reclaiming space...\n");
 714    DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
 715    /* Pick the least erased transfer unit */
 716    best = 0xffffffff; xfer = 0xffff;
 717    do {
 718        queued = 0;
 719        for (i = 0; i < part->header.NumTransferUnits; i++) {
 720            int n=0;
 721            if (part->XferInfo[i].state == XFER_UNKNOWN) {
 722                DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
 723                n=1;
 724                erase_xfer(part, i);
 725            }
 726            if (part->XferInfo[i].state == XFER_ERASING) {
 727                DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i);
 728                n=1;
 729                queued = 1;
 730            }
 731            else if (part->XferInfo[i].state == XFER_ERASED) {
 732                DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i);
 733                n=1;
 734                prepare_xfer(part, i);
 735            }
 736            if (part->XferInfo[i].state == XFER_PREPARED) {
 737                DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i);
 738                n=1;
 739                if (part->XferInfo[i].EraseCount <= best) {
 740                    best = part->XferInfo[i].EraseCount;
 741                    xfer = i;
 742                }
 743            }
 744                if (!n)
 745                    DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
 746
 747        }
 748        if (xfer == 0xffff) {
 749            if (queued) {
 750                DEBUG(1, "ftl_cs: waiting for transfer "
 751                      "unit to be prepared...\n");
 752                if (part->mtd->sync)
 753                        part->mtd->sync(part->mtd);
 754            } else {
 755                static int ne = 0;
 756                if (++ne < 5)
 757                    printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
 758                           "suitable transfer units!\n");
 759                else
 760                    DEBUG(1, "ftl_cs: reclaim failed: no "
 761                          "suitable transfer units!\n");
 762                        
 763                return -EIO;
 764            }
 765        }
 766    } while (xfer == 0xffff);
 767
 768    eun = 0;
 769    if ((jiffies % shuffle_freq) == 0) {
 770        DEBUG(1, "ftl_cs: recycling freshest block...\n");
 771        best = 0xffffffff;
 772        for (i = 0; i < part->DataUnits; i++)
 773            if (part->EUNInfo[i].EraseCount <= best) {
 774                best = part->EUNInfo[i].EraseCount;
 775                eun = i;
 776            }
 777    } else {
 778        best = 0;
 779        for (i = 0; i < part->DataUnits; i++)
 780            if (part->EUNInfo[i].Deleted >= best) {
 781                best = part->EUNInfo[i].Deleted;
 782                eun = i;
 783            }
 784        if (best == 0) {
 785            static int ne = 0;
 786            if (++ne < 5)
 787                printk(KERN_NOTICE "ftl_cs: reclaim failed: "
 788                       "no free blocks!\n");
 789            else
 790                DEBUG(1,"ftl_cs: reclaim failed: "
 791                       "no free blocks!\n");
 792
 793            return -EIO;
 794        }
 795    }
 796    ret = copy_erase_unit(part, eun, xfer);
 797    if (!ret)
 798        erase_xfer(part, xfer);
 799    else
 800        printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
 801    return ret;
 802} /* reclaim_block */
 803
 804/*======================================================================
 805
 806    Find_free() searches for a free block.  If necessary, it updates
 807    the BAM cache for the erase unit containing the free block.  It
 808    returns the block index -- the erase unit is just the currently
 809    cached unit.  If there are no free blocks, it returns 0 -- this
 810    is never a valid data block because it contains the header.
 811    
 812======================================================================*/
 813
 814#ifdef PSYCHO_DEBUG
 815static void dump_lists(partition_t *part)
 816{
 817    int i;
 818    printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
 819    for (i = 0; i < part->DataUnits; i++)
 820        printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
 821               "%d deleted\n", i,
 822               part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
 823               part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
 824}
 825#endif
 826
 827static u_int32_t find_free(partition_t *part)
 828{
 829    u_int16_t stop, eun;
 830    u_int32_t blk;
 831    size_t retlen;
 832    int ret;
 833    
 834    /* Find an erase unit with some free space */
 835    stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
 836    eun = stop;
 837    do {
 838        if (part->EUNInfo[eun].Free != 0) break;
 839        /* Wrap around at end of table */
 840        if (++eun == part->DataUnits) eun = 0;
 841    } while (eun != stop);
 842
 843    if (part->EUNInfo[eun].Free == 0)
 844        return 0;
 845    
 846    /* Is this unit's BAM cached? */
 847    if (eun != part->bam_index) {
 848        /* Invalidate cache */
 849        part->bam_index = 0xffff;
 850
 851        ret = part->mtd->read(part->mtd, 
 852                       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
 853                       part->BlocksPerUnit * sizeof(u_int32_t),
 854                       &retlen, (u_char *) (part->bam_cache));
 855        
 856        if (ret) {
 857            printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
 858            return 0;
 859        }
 860        part->bam_index = eun;
 861    }
 862
 863    /* Find a free block */
 864    for (blk = 0; blk < part->BlocksPerUnit; blk++)
 865        if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
 866    if (blk == part->BlocksPerUnit) {
 867#ifdef PSYCHO_DEBUG
 868        static int ne = 0;
 869        if (++ne == 1)
 870            dump_lists(part);
 871#endif
 872        printk(KERN_NOTICE "ftl_cs: bad free list!\n");
 873        return 0;
 874    }
 875    DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
 876    return blk;
 877    
 878} /* find_free */
 879
 880/*======================================================================
 881
 882    This gets a memory handle for the region corresponding to the
 883    minor device number.
 884    
 885======================================================================*/
 886
 887static int ftl_open(struct inode *inode, struct file *file)
 888{
 889    int minor = MINOR(inode->i_rdev);
 890    partition_t *partition;
 891
 892    if (minor>>4 >= MAX_MTD_DEVICES)
 893        return -ENODEV;
 894
 895    partition = myparts[minor>>4];
 896
 897    if (!partition)
 898        return -ENODEV;
 899
 900    if (partition->state != FTL_FORMATTED)
 901        return -ENXIO;
 902    
 903    if (ftl_gendisk.part[minor].nr_sects == 0)
 904        return -ENXIO;
 905
 906    BLK_INC_USE_COUNT;
 907
 908    if (!get_mtd_device(partition->mtd, -1)) {
 909            BLK_DEC_USE_COUNT;
 910            return -ENXIO;
 911    }
 912    
 913    if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
 914            put_mtd_device(partition->mtd);
 915            BLK_DEC_USE_COUNT;
 916            return -EROFS;
 917    }
 918    
 919    DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
 920
 921    atomic_inc(&partition->open);
 922
 923    return 0;
 924}
 925
 926/*====================================================================*/
 927
 928static release_t ftl_close(struct inode *inode, struct file *file)
 929{
 930    int minor = MINOR(inode->i_rdev);
 931    partition_t *part = myparts[minor >> 4];
 932    int i;
 933    
 934    DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
 935
 936    /* Wait for any pending erase operations to complete */
 937    if (part->mtd->sync)
 938            part->mtd->sync(part->mtd);
 939    
 940    for (i = 0; i < part->header.NumTransferUnits; i++) {
 941        if (part->XferInfo[i].state == XFER_ERASED)
 942            prepare_xfer(part, i);
 943    }
 944
 945    atomic_dec(&part->open);
 946
 947    put_mtd_device(part->mtd);
 948    BLK_DEC_USE_COUNT;
 949    release_return(0);
 950} /* ftl_close */
 951
 952
 953/*======================================================================
 954
 955    Read a series of sectors from an FTL partition.
 956    
 957======================================================================*/
 958
 959static int ftl_read(partition_t *part, caddr_t buffer,
 960                    u_long sector, u_long nblocks)
 961{
 962    u_int32_t log_addr, bsize;
 963    u_long i;
 964    int ret;
 965    size_t offset, retlen;
 966    
 967    DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
 968          part, sector, nblocks);
 969    if (!(part->state & FTL_FORMATTED)) {
 970        printk(KERN_NOTICE "ftl_cs: bad partition\n");
 971        return -EIO;
 972    }
 973    bsize = 1 << part->header.EraseUnitSize;
 974
 975    for (i = 0; i < nblocks; i++) {
 976        if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
 977            printk(KERN_NOTICE "ftl_cs: bad read offset\n");
 978            return -EIO;
 979        }
 980        log_addr = part->VirtualBlockMap[sector+i];
 981        if (log_addr == 0xffffffff)
 982            memset(buffer, 0, SECTOR_SIZE);
 983        else {
 984            offset = (part->EUNInfo[log_addr / bsize].Offset
 985                          + (log_addr % bsize));
 986            ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
 987                           &retlen, (u_char *) buffer);
 988
 989            if (ret) {
 990                printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
 991                return ret;
 992            }
 993        }
 994        buffer += SECTOR_SIZE;
 995    }
 996    return 0;
 997} /* ftl_read */
 998
 999/*======================================================================
1000
1001    Write a series of sectors to an FTL partition
1002    
1003======================================================================*/
1004
1005static int set_bam_entry(partition_t *part, u_int32_t log_addr,
1006                         u_int32_t virt_addr)
1007{
1008    u_int32_t bsize, blk, le_virt_addr;
1009#ifdef PSYCHO_DEBUG
1010    u_int32_t old_addr;
1011#endif
1012    u_int16_t eun;
1013    int ret;
1014    size_t retlen, offset;
1015
1016    DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
1017          part, log_addr, virt_addr);
1018    bsize = 1 << part->header.EraseUnitSize;
1019    eun = log_addr / bsize;
1020    blk = (log_addr % bsize) / SECTOR_SIZE;
1021    offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
1022                  le32_to_cpu(part->header.BAMOffset));
1023    
1024#ifdef PSYCHO_DEBUG
1025    ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
1026                        &retlen, (u_char *)&old_addr);
1027    if (ret) {
1028        printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
1029        return ret;
1030    }
1031    old_addr = le32_to_cpu(old_addr);
1032
1033    if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
1034        ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
1035        (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
1036        static int ne = 0;
1037        if (++ne < 5) {
1038            printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
1039            printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"
1040                   ", new = 0x%x\n", log_addr, old_addr, virt_addr);
1041        }
1042        return -EIO;
1043    }
1044#endif
1045    le_virt_addr = cpu_to_le32(virt_addr);
1046    if (part->bam_index == eun) {
1047#ifdef PSYCHO_DEBUG
1048        if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
1049            static int ne = 0;
1050            if (++ne < 5) {
1051                printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
1052                       "inconsistency!\n");
1053                printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"
1054                       " = 0x%x\n",
1055                       le32_to_cpu(part->bam_cache[blk]), old_addr);
1056            }
1057            return -EIO;
1058        }
1059#endif
1060        part->bam_cache[blk] = le_virt_addr;
1061    }
1062    ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
1063                            &retlen, (u_char *)&le_virt_addr);
1064
1065    if (ret) {
1066        printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
1067        printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",
1068               log_addr, virt_addr);
1069    }
1070    return ret;
1071} /* set_bam_entry */
1072
1073static int ftl_write(partition_t *part, caddr_t buffer,
1074                     u_long sector, u_long nblocks)
1075{
1076    u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
1077    u_long i;
1078    int ret;
1079    size_t retlen, offset;
1080
1081    DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
1082          part, sector, nblocks);
1083    if (!(part->state & FTL_FORMATTED)) {
1084        printk(KERN_NOTICE "ftl_cs: bad partition\n");
1085        return -EIO;
1086    }
1087    /* See if we need to reclaim space, before we start */
1088    while (part->FreeTotal < nblocks) {
1089        ret = reclaim_block(part);
1090        if (ret)
1091            return ret;
1092    }
1093    
1094    bsize = 1 << part->header.EraseUnitSize;
1095
1096    virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
1097    for (i = 0; i < nblocks; i++) {
1098        if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
1099            printk(KERN_NOTICE "ftl_cs: bad write offset\n");
1100            return -EIO;
1101        }
1102
1103        /* Grab a free block */
1104        blk = find_free(part);
1105        if (blk == 0) {
1106            static int ne = 0;
1107            if (++ne < 5)
1108                printk(KERN_NOTICE "ftl_cs: internal error: "
1109                       "no free blocks!\n");
1110            return -ENOSPC;
1111        }
1112
1113        /* Tag the BAM entry, and write the new block */
1114        log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
1115        part->EUNInfo[part->bam_index].Free--;
1116        part->FreeTotal--;
1117        if (set_bam_entry(part, log_addr, 0xfffffffe)) 
1118            return -EIO;
1119        part->EUNInfo[part->bam_index].Deleted++;
1120        offset = (part->EUNInfo[part->bam_index].Offset +
1121                      blk * SECTOR_SIZE);
1122        ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen, 
1123                                     buffer);
1124
1125        if (ret) {
1126            printk(KERN_NOTICE "ftl_cs: block write failed!\n");
1127            printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
1128                   " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
1129                   offset);
1130            return -EIO;
1131        }
1132        
1133        /* Only delete the old entry when the new entry is ready */
1134        old_addr = part->VirtualBlockMap[sector+i];
1135        if (old_addr != 0xffffffff) {
1136            part->VirtualBlockMap[sector+i] = 0xffffffff;
1137            part->EUNInfo[old_addr/bsize].Deleted++;
1138            if (set_bam_entry(part, old_addr, 0))
1139                return -EIO;
1140        }
1141
1142        /* Finally, set up the new pointers */
1143        if (set_bam_entry(part, log_addr, virt_addr))
1144            return -EIO;
1145        part->VirtualBlockMap[sector+i] = log_addr;
1146        part->EUNInfo[part->bam_index].Deleted--;
1147        
1148        buffer += SECTOR_SIZE;
1149        virt_addr += SECTOR_SIZE;
1150    }
1151    return 0;
1152} /* ftl_write */
1153
1154/*======================================================================
1155
1156    IOCTL calls for getting device parameters.
1157
1158======================================================================*/
1159
1160static int ftl_ioctl(struct inode *inode, struct file *file,
1161                     u_int cmd, u_long arg)
1162{
1163    struct hd_geometry *geo = (struct hd_geometry *)arg;
1164    int ret = 0, minor = MINOR(inode->i_rdev);
1165    partition_t *part= myparts[minor >> 4];
1166    u_long sect;
1167
1168    if (!part)
1169        return -ENODEV; /* How? */
1170
1171    switch (cmd) {
1172    case HDIO_GETGEO:
1173        ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
1174        if (ret) return ret;
1175        /* Sort of arbitrary: round size down to 4K boundary */
1176        sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
1177        put_user(1, (char *)&geo->heads);
1178        put_user(8, (char *)&geo->sectors);
1179        put_user((sect>>3), (short *)&geo->cylinders);
1180        put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
1181        break;
1182    case BLKGETSIZE:
1183        ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg);
1184        break;
1185#ifdef BLKGETSIZE64
1186    case BLKGETSIZE64:
1187        ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
1188        break;
1189#endif
1190    case BLKRRPART:
1191        ret = ftl_reread_partitions(minor);
1192        break;
1193#if (LINUX_VERSION_CODE < 0x20303)
1194    case BLKFLSBUF:
1195#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
1196        if (!capable(CAP_SYS_ADMIN)) return -EACCES;
1197#endif
1198        fsync_dev(inode->i_rdev);
1199        invalidate_buffers(inode->i_rdev);
1200        break;
1201    RO_IOCTLS(inode->i_rdev, arg);
1202#else
1203    case BLKROSET:
1204    case BLKROGET:
1205    case BLKFLSBUF:
1206        ret = blk_ioctl(inode->i_rdev, cmd, arg);
1207        break;
1208#endif
1209    default:
1210        ret = -EINVAL;
1211    }
1212
1213    return ret;
1214} /* ftl_ioctl */
1215
1216/*======================================================================
1217
1218    Handler for block device requests
1219
1220======================================================================*/
1221
1222static int ftl_reread_partitions(int minor)
1223{
1224    partition_t *part = myparts[minor >> 4];
1225    int i, whole;
1226
1227    DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
1228    if ((atomic_read(&part->open) > 1)) {
1229            return -EBUSY;
1230    }
1231    whole = minor & ~(MAX_PART-1);
1232
1233    i = MAX_PART - 1;
1234    while (i-- > 0) {
1235        if (ftl_hd[whole+i].nr_sects > 0) {
1236            kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);
1237
1238            invalidate_device(rdev, 1);
1239        }
1240        ftl_hd[whole+i].start_sect = 0;
1241        ftl_hd[whole+i].nr_sects = 0;
1242    }
1243
1244    scan_header(part);
1245
1246    register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
1247                  &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
1248
1249#ifdef PCMCIA_DEBUG
1250    for (i = 0; i < MAX_PART; i++) {
1251        if (ftl_hd[whole+i].nr_sects > 0)
1252            printk(KERN_INFO "  %d: start %ld size %ld\n", i,
1253                   ftl_hd[whole+i].start_sect,
1254                   ftl_hd[whole+i].nr_sects);
1255    }
1256#endif
1257    return 0;
1258}
1259
1260/*======================================================================
1261
1262    Handler for block device requests
1263
1264======================================================================*/
1265
1266static void do_ftl_request(request_arg_t)
1267{
1268    int ret, minor;
1269    partition_t *part;
1270
1271    do {
1272      //            sti();
1273        INIT_REQUEST;
1274
1275        minor = MINOR(CURRENT->rq_dev);
1276        
1277        part = myparts[minor >> 4];
1278        if (part) {
1279          ret = 0;
1280          
1281          switch (CURRENT->cmd) {
1282          case READ:
1283            ret = ftl_read(part, CURRENT->buffer,
1284                           CURRENT->sector+ftl_hd[minor].start_sect,
1285                           CURRENT->current_nr_sectors);
1286            if (ret) printk("ftl_read returned %d\n", ret);
1287            break;
1288            
1289          case WRITE:
1290            ret = ftl_write(part, CURRENT->buffer,
1291                            CURRENT->sector+ftl_hd[minor].start_sect,
1292                            CURRENT->current_nr_sectors);
1293            if (ret) printk("ftl_write returned %d\n", ret);
1294            break;
1295            
1296          default:
1297            panic("ftl_cs: unknown block command!\n");
1298            
1299          }
1300        } else {
1301          ret = 1;
1302          printk("NULL part in ftl_request\n");
1303        }
1304         
1305        if (!ret) {
1306          CURRENT->sector += CURRENT->current_nr_sectors;
1307        }
1308        
1309        end_request((ret == 0) ? 1 : 0);
1310    } while (1);
1311} /* do_ftl_request */
1312
1313/*====================================================================*/
1314
1315void ftl_freepart(partition_t *part)
1316{
1317    if (part->VirtualBlockMap) {
1318        vfree(part->VirtualBlockMap);
1319        part->VirtualBlockMap = NULL;
1320    }
1321    if (part->VirtualPageMap) {
1322        kfree(part->VirtualPageMap);
1323        part->VirtualPageMap = NULL;
1324    }
1325    if (part->EUNInfo) {
1326        kfree(part->EUNInfo);
1327        part->EUNInfo = NULL;
1328    }
1329    if (part->XferInfo) {
1330        kfree(part->XferInfo);
1331        part->XferInfo = NULL;
1332    }
1333    if (part->bam_cache) {
1334        kfree(part->bam_cache);
1335        part->bam_cache = NULL;
1336    }
1337    
1338} /* ftl_freepart */
1339
1340static void ftl_notify_add(struct mtd_info *mtd)
1341{
1342        partition_t *partition;
1343        int device;
1344
1345        for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
1346                ;
1347
1348        if (device == MAX_MTD_DEVICES) {
1349                printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
1350                       "Not scanning <%s>\n", mtd->name);
1351                return;
1352        }
1353
1354        partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
1355                
1356        if (!partition) {
1357                printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1358                       mtd->name);
1359                return;
1360        }    
1361
1362        memset(partition, 0, sizeof(partition_t));
1363
1364        partition->mtd = mtd;
1365
1366        if ((scan_header(partition) == 0) && 
1367            (build_maps(partition) == 0)) {
1368                
1369                partition->state = FTL_FORMATTED;
1370                atomic_set(&partition->open, 0);
1371                myparts[device] = partition;
1372                ftl_reread_partitions(device << 4);
1373#ifdef PCMCIA_DEBUG
1374                printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
1375                       le32_to_cpu(partition->header.FormattedSize) >> 10);
1376#endif
1377        } else
1378                kfree(partition);
1379}
1380
1381static void ftl_notify_remove(struct mtd_info *mtd)
1382{
1383        int i,j;
1384
1385        /* Q: What happens if you try to remove a device which has
1386         *    a currently-open FTL partition on it?
1387         *
1388         * A: You don't. The ftl_open routine is responsible for
1389         *    increasing the use count of the driver module which
1390         *    it uses.
1391         */
1392
1393        /* That's the theory, anyway :) */
1394
1395        for (i=0; i< MAX_MTD_DEVICES; i++)
1396                if (myparts[i] && myparts[i]->mtd == mtd) {
1397
1398                        if (myparts[i]->state == FTL_FORMATTED)
1399                                ftl_freepart(myparts[i]);
1400                        
1401                        myparts[i]->state = 0;
1402                        for (j=0; j<16; j++) {
1403                                ftl_gendisk.part[j].nr_sects=0;
1404                                ftl_gendisk.part[j].start_sect=0;
1405                        }
1406                        kfree(myparts[i]);
1407                        myparts[i] = NULL;
1408                }
1409}
1410
1411int init_ftl(void)
1412{
1413    int i;
1414
1415    memset(myparts, 0, sizeof(myparts));
1416    
1417    DEBUG(0, "$Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $\n");
1418    
1419    if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
1420        printk(KERN_NOTICE "ftl_cs: unable to grab major "
1421               "device number!\n");
1422        return -EAGAIN;
1423    }
1424    
1425    for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
1426        ftl_blocksizes[i] = 1024;
1427    for (i = 0; i < MAX_DEV*MAX_PART; i++) {
1428        ftl_hd[i].nr_sects = 0;
1429        ftl_hd[i].start_sect = 0;
1430    }
1431    blksize_size[FTL_MAJOR] = ftl_blocksizes;
1432    ftl_gendisk.major = FTL_MAJOR;
1433    blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
1434    add_gendisk(&ftl_gendisk);
1435    
1436    register_mtd_user(&ftl_notifier);
1437    
1438    return 0;
1439}
1440
1441static void __exit cleanup_ftl(void)
1442{
1443    unregister_mtd_user(&ftl_notifier);
1444
1445    unregister_blkdev(FTL_MAJOR, "ftl");
1446    blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
1447    blksize_size[FTL_MAJOR] = NULL;
1448
1449    del_gendisk(&ftl_gendisk);
1450}
1451
1452module_init(init_ftl);
1453module_exit(cleanup_ftl);
1454
1455
1456MODULE_LICENSE("Dual MPL/GPL");
1457MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1458MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
1459
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.