Back to home page

OSCL-LXR

 
 

    


0001 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
0002  *
0003  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
0004  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
0005  *
0006  * Based on:
0007  */
0008 /*======================================================================
0009 
0010     A Flash Translation Layer memory card driver
0011 
0012     This driver implements a disk-like block device driver with an
0013     apparent block size of 512 bytes for flash memory cards.
0014 
0015     ftl_cs.c 1.62 2000/02/01 00:59:04
0016 
0017     The contents of this file are subject to the Mozilla Public
0018     License Version 1.1 (the "License"); you may not use this file
0019     except in compliance with the License. You may obtain a copy of
0020     the License at http://www.mozilla.org/MPL/
0021 
0022     Software distributed under the License is distributed on an "AS
0023     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0024     implied. See the License for the specific language governing
0025     rights and limitations under the License.
0026 
0027     The initial developer of the original code is David A. Hinds
0028     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
0029     are Copyright © 1999 David A. Hinds.  All Rights Reserved.
0030 
0031     Alternatively, the contents of this file may be used under the
0032     terms of the GNU General Public License version 2 (the "GPL"), in
0033     which case the provisions of the GPL are applicable instead of the
0034     above.  If you wish to allow the use of your version of this file
0035     only under the terms of the GPL and not to allow others to use
0036     your version of this file under the MPL, indicate your decision
0037     by deleting the provisions above and replace them with the notice
0038     and other provisions required by the GPL.  If you do not delete
0039     the provisions above, a recipient may use your version of this
0040     file under either the MPL or the GPL.
0041 
0042     LEGAL NOTE: The FTL format is patented by M-Systems.  They have
0043     granted a license for its use with PCMCIA devices:
0044 
0045      "M-Systems grants a royalty-free, non-exclusive license under
0046       any presently existing M-Systems intellectual property rights
0047       necessary for the design and development of FTL-compatible
0048       drivers, file systems and utilities using the data formats with
0049       PCMCIA PC Cards as described in the PCMCIA Flash Translation
0050       Layer (FTL) Specification."
0051 
0052     Use of the FTL format for non-PCMCIA applications may be an
0053     infringement of these patents.  For additional information,
0054     contact M-Systems directly. M-Systems since acquired by Sandisk. 
0055 
0056 ======================================================================*/
0057 #include <linux/mtd/blktrans.h>
0058 #include <linux/module.h>
0059 #include <linux/mtd/mtd.h>
0060 /*#define PSYCHO_DEBUG */
0061 
0062 #include <linux/kernel.h>
0063 #include <linux/ptrace.h>
0064 #include <linux/slab.h>
0065 #include <linux/string.h>
0066 #include <linux/timer.h>
0067 #include <linux/major.h>
0068 #include <linux/fs.h>
0069 #include <linux/init.h>
0070 #include <linux/hdreg.h>
0071 #include <linux/vmalloc.h>
0072 #include <linux/blkpg.h>
0073 #include <linux/uaccess.h>
0074 
0075 #include <linux/mtd/ftl.h>
0076 
0077 /*====================================================================*/
0078 
0079 /* Parameters that can be set with 'insmod' */
0080 static int shuffle_freq = 50;
0081 module_param(shuffle_freq, int, 0);
0082 
0083 /*====================================================================*/
0084 
0085 /* Major device # for FTL device */
0086 #ifndef FTL_MAJOR
0087 #define FTL_MAJOR   44
0088 #endif
0089 
0090 
0091 /*====================================================================*/
0092 
0093 /* Maximum number of separate memory devices we'll allow */
0094 #define MAX_DEV     4
0095 
0096 /* Maximum number of regions per device */
0097 #define MAX_REGION  4
0098 
0099 /* Maximum number of partitions in an FTL region */
0100 #define PART_BITS   4
0101 
0102 /* Maximum number of outstanding erase requests per socket */
0103 #define MAX_ERASE   8
0104 
0105 /* Sector size -- shouldn't need to change */
0106 #define SECTOR_SIZE 512
0107 
0108 
0109 /* Each memory region corresponds to a minor device */
0110 typedef struct partition_t {
0111     struct mtd_blktrans_dev mbd;
0112     uint32_t        state;
0113     uint32_t        *VirtualBlockMap;
0114     uint32_t        FreeTotal;
0115     struct eun_info_t {
0116     uint32_t        Offset;
0117     uint32_t        EraseCount;
0118     uint32_t        Free;
0119     uint32_t        Deleted;
0120     } *EUNInfo;
0121     struct xfer_info_t {
0122     uint32_t        Offset;
0123     uint32_t        EraseCount;
0124     uint16_t        state;
0125     } *XferInfo;
0126     uint16_t        bam_index;
0127     uint32_t        *bam_cache;
0128     uint16_t        DataUnits;
0129     uint32_t        BlocksPerUnit;
0130     erase_unit_header_t header;
0131 } partition_t;
0132 
0133 /* Partition state flags */
0134 #define FTL_FORMATTED   0x01
0135 
0136 /* Transfer unit states */
0137 #define XFER_UNKNOWN    0x00
0138 #define XFER_ERASING    0x01
0139 #define XFER_ERASED 0x02
0140 #define XFER_PREPARED   0x03
0141 #define XFER_FAILED 0x04
0142 
0143 /*======================================================================
0144 
0145     Scan_header() checks to see if a memory region contains an FTL
0146     partition.  build_maps() reads all the erase unit headers, builds
0147     the erase unit map, and then builds the virtual page map.
0148 
0149 ======================================================================*/
0150 
0151 static int scan_header(partition_t *part)
0152 {
0153     erase_unit_header_t header;
0154     loff_t offset, max_offset;
0155     size_t ret;
0156     int err;
0157     part->header.FormattedSize = 0;
0158     max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
0159     /* Search first megabyte for a valid FTL header */
0160     for (offset = 0;
0161      (offset + sizeof(header)) < max_offset;
0162      offset += part->mbd.mtd->erasesize ? : 0x2000) {
0163 
0164     err = mtd_read(part->mbd.mtd, offset, sizeof(header), &ret,
0165                        (unsigned char *)&header);
0166 
0167     if (err)
0168         return err;
0169 
0170     if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
0171     }
0172 
0173     if (offset == max_offset) {
0174     printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
0175     return -ENOENT;
0176     }
0177     if (header.BlockSize != 9 ||
0178     (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
0179     (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
0180     printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
0181     return -1;
0182     }
0183     if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
0184     printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
0185            1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
0186     return -1;
0187     }
0188     part->header = header;
0189     return 0;
0190 }
0191 
0192 static int build_maps(partition_t *part)
0193 {
0194     erase_unit_header_t header;
0195     uint16_t xvalid, xtrans, i;
0196     unsigned blocks, j;
0197     int hdr_ok, ret = -1;
0198     ssize_t retval;
0199     loff_t offset;
0200 
0201     /* Set up erase unit maps */
0202     part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
0203     part->header.NumTransferUnits;
0204     part->EUNInfo = kmalloc_array(part->DataUnits, sizeof(struct eun_info_t),
0205                                   GFP_KERNEL);
0206     if (!part->EUNInfo)
0207         goto out;
0208     for (i = 0; i < part->DataUnits; i++)
0209     part->EUNInfo[i].Offset = 0xffffffff;
0210     part->XferInfo =
0211     kmalloc_array(part->header.NumTransferUnits,
0212                       sizeof(struct xfer_info_t),
0213                       GFP_KERNEL);
0214     if (!part->XferInfo)
0215         goto out_EUNInfo;
0216 
0217     xvalid = xtrans = 0;
0218     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
0219     offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
0220               << part->header.EraseUnitSize);
0221     ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval,
0222                        (unsigned char *)&header);
0223 
0224     if (ret)
0225         goto out_XferInfo;
0226 
0227     ret = -1;
0228     /* Is this a transfer partition? */
0229     hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
0230     if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
0231         (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
0232         part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
0233         part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
0234         le32_to_cpu(header.EraseCount);
0235         xvalid++;
0236     } else {
0237         if (xtrans == part->header.NumTransferUnits) {
0238         printk(KERN_NOTICE "ftl_cs: format error: too many "
0239                "transfer units!\n");
0240         goto out_XferInfo;
0241         }
0242         if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
0243         part->XferInfo[xtrans].state = XFER_PREPARED;
0244         part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
0245         } else {
0246         part->XferInfo[xtrans].state = XFER_UNKNOWN;
0247         /* Pick anything reasonable for the erase count */
0248         part->XferInfo[xtrans].EraseCount =
0249             le32_to_cpu(part->header.EraseCount);
0250         }
0251         part->XferInfo[xtrans].Offset = offset;
0252         xtrans++;
0253     }
0254     }
0255     /* Check for format trouble */
0256     header = part->header;
0257     if ((xtrans != header.NumTransferUnits) ||
0258     (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
0259     printk(KERN_NOTICE "ftl_cs: format error: erase units "
0260            "don't add up!\n");
0261     goto out_XferInfo;
0262     }
0263 
0264     /* Set up virtual page map */
0265     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
0266     part->VirtualBlockMap = vmalloc(array_size(blocks, sizeof(uint32_t)));
0267     if (!part->VirtualBlockMap)
0268         goto out_XferInfo;
0269 
0270     memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
0271     part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
0272 
0273     part->bam_cache = kmalloc_array(part->BlocksPerUnit, sizeof(uint32_t),
0274                                     GFP_KERNEL);
0275     if (!part->bam_cache)
0276         goto out_VirtualBlockMap;
0277 
0278     part->bam_index = 0xffff;
0279     part->FreeTotal = 0;
0280 
0281     for (i = 0; i < part->DataUnits; i++) {
0282     part->EUNInfo[i].Free = 0;
0283     part->EUNInfo[i].Deleted = 0;
0284     offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
0285 
0286     ret = mtd_read(part->mbd.mtd, offset,
0287                        part->BlocksPerUnit * sizeof(uint32_t), &retval,
0288                        (unsigned char *)part->bam_cache);
0289 
0290     if (ret)
0291         goto out_bam_cache;
0292 
0293     for (j = 0; j < part->BlocksPerUnit; j++) {
0294         if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
0295         part->EUNInfo[i].Free++;
0296         part->FreeTotal++;
0297         } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
0298              (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
0299         part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
0300             (i << header.EraseUnitSize) + (j << header.BlockSize);
0301         else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
0302         part->EUNInfo[i].Deleted++;
0303     }
0304     }
0305 
0306     ret = 0;
0307     goto out;
0308 
0309 out_bam_cache:
0310     kfree(part->bam_cache);
0311 out_VirtualBlockMap:
0312     vfree(part->VirtualBlockMap);
0313 out_XferInfo:
0314     kfree(part->XferInfo);
0315 out_EUNInfo:
0316     kfree(part->EUNInfo);
0317 out:
0318     return ret;
0319 } /* build_maps */
0320 
0321 /*======================================================================
0322 
0323     Erase_xfer() schedules an asynchronous erase operation for a
0324     transfer unit.
0325 
0326 ======================================================================*/
0327 
0328 static int erase_xfer(partition_t *part,
0329               uint16_t xfernum)
0330 {
0331     int ret;
0332     struct xfer_info_t *xfer;
0333     struct erase_info *erase;
0334 
0335     xfer = &part->XferInfo[xfernum];
0336     pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
0337     xfer->state = XFER_ERASING;
0338 
0339     /* Is there a free erase slot? Always in MTD. */
0340 
0341 
0342     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
0343     if (!erase)
0344             return -ENOMEM;
0345 
0346     erase->addr = xfer->Offset;
0347     erase->len = 1 << part->header.EraseUnitSize;
0348 
0349     ret = mtd_erase(part->mbd.mtd, erase);
0350     if (!ret) {
0351     xfer->state = XFER_ERASED;
0352     xfer->EraseCount++;
0353     } else {
0354     xfer->state = XFER_FAILED;
0355     pr_notice("ftl_cs: erase failed: err = %d\n", ret);
0356     }
0357 
0358     kfree(erase);
0359 
0360     return ret;
0361 } /* erase_xfer */
0362 
0363 /*======================================================================
0364 
0365     Prepare_xfer() takes a freshly erased transfer unit and gives
0366     it an appropriate header.
0367 
0368 ======================================================================*/
0369 
0370 static int prepare_xfer(partition_t *part, int i)
0371 {
0372     erase_unit_header_t header;
0373     struct xfer_info_t *xfer;
0374     int nbam, ret;
0375     uint32_t ctl;
0376     ssize_t retlen;
0377     loff_t offset;
0378 
0379     xfer = &part->XferInfo[i];
0380     xfer->state = XFER_FAILED;
0381 
0382     pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
0383 
0384     /* Write the transfer unit header */
0385     header = part->header;
0386     header.LogicalEUN = cpu_to_le16(0xffff);
0387     header.EraseCount = cpu_to_le32(xfer->EraseCount);
0388 
0389     ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen,
0390                     (u_char *)&header);
0391 
0392     if (ret) {
0393     return ret;
0394     }
0395 
0396     /* Write the BAM stub */
0397     nbam = DIV_ROUND_UP(part->BlocksPerUnit * sizeof(uint32_t) +
0398             le32_to_cpu(part->header.BAMOffset), SECTOR_SIZE);
0399 
0400     offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
0401     ctl = cpu_to_le32(BLOCK_CONTROL);
0402 
0403     for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
0404 
0405     ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
0406                         (u_char *)&ctl);
0407 
0408     if (ret)
0409         return ret;
0410     }
0411     xfer->state = XFER_PREPARED;
0412     return 0;
0413 
0414 } /* prepare_xfer */
0415 
0416 /*======================================================================
0417 
0418     Copy_erase_unit() takes a full erase block and a transfer unit,
0419     copies everything to the transfer unit, then swaps the block
0420     pointers.
0421 
0422     All data blocks are copied to the corresponding blocks in the
0423     target unit, so the virtual block map does not need to be
0424     updated.
0425 
0426 ======================================================================*/
0427 
0428 static int copy_erase_unit(partition_t *part, uint16_t srcunit,
0429                uint16_t xferunit)
0430 {
0431     u_char buf[SECTOR_SIZE];
0432     struct eun_info_t *eun;
0433     struct xfer_info_t *xfer;
0434     uint32_t src, dest, free, i;
0435     uint16_t unit;
0436     int ret;
0437     ssize_t retlen;
0438     loff_t offset;
0439     uint16_t srcunitswap = cpu_to_le16(srcunit);
0440 
0441     eun = &part->EUNInfo[srcunit];
0442     xfer = &part->XferInfo[xferunit];
0443     pr_debug("ftl_cs: copying block 0x%x to 0x%x\n",
0444       eun->Offset, xfer->Offset);
0445 
0446 
0447     /* Read current BAM */
0448     if (part->bam_index != srcunit) {
0449 
0450     offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
0451 
0452     ret = mtd_read(part->mbd.mtd, offset,
0453                        part->BlocksPerUnit * sizeof(uint32_t), &retlen,
0454                        (u_char *)(part->bam_cache));
0455 
0456     /* mark the cache bad, in case we get an error later */
0457     part->bam_index = 0xffff;
0458 
0459     if (ret) {
0460         printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
0461         return ret;
0462     }
0463     }
0464 
0465     /* Write the LogicalEUN for the transfer unit */
0466     xfer->state = XFER_UNKNOWN;
0467     offset = xfer->Offset + 20; /* Bad! */
0468     unit = cpu_to_le16(0x7fff);
0469 
0470     ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen,
0471                     (u_char *)&unit);
0472 
0473     if (ret) {
0474     printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
0475     return ret;
0476     }
0477 
0478     /* Copy all data blocks from source unit to transfer unit */
0479     src = eun->Offset; dest = xfer->Offset;
0480 
0481     free = 0;
0482     ret = 0;
0483     for (i = 0; i < part->BlocksPerUnit; i++) {
0484     switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
0485     case BLOCK_CONTROL:
0486         /* This gets updated later */
0487         break;
0488     case BLOCK_DATA:
0489     case BLOCK_REPLACEMENT:
0490         ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen,
0491                            (u_char *)buf);
0492         if (ret) {
0493         printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
0494         return ret;
0495             }
0496 
0497 
0498         ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen,
0499                             (u_char *)buf);
0500         if (ret)  {
0501         printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
0502         return ret;
0503             }
0504 
0505         break;
0506     default:
0507         /* All other blocks must be free */
0508         part->bam_cache[i] = cpu_to_le32(0xffffffff);
0509         free++;
0510         break;
0511     }
0512     src += SECTOR_SIZE;
0513     dest += SECTOR_SIZE;
0514     }
0515 
0516     /* Write the BAM to the transfer unit */
0517     ret = mtd_write(part->mbd.mtd,
0518                     xfer->Offset + le32_to_cpu(part->header.BAMOffset),
0519                     part->BlocksPerUnit * sizeof(int32_t),
0520                     &retlen,
0521                     (u_char *)part->bam_cache);
0522     if (ret) {
0523     printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
0524     return ret;
0525     }
0526 
0527 
0528     /* All clear? Then update the LogicalEUN again */
0529     ret = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
0530                     &retlen, (u_char *)&srcunitswap);
0531 
0532     if (ret) {
0533     printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
0534     return ret;
0535     }
0536 
0537 
0538     /* Update the maps and usage stats*/
0539     swap(xfer->EraseCount, eun->EraseCount);
0540     swap(xfer->Offset, eun->Offset);
0541     part->FreeTotal -= eun->Free;
0542     part->FreeTotal += free;
0543     eun->Free = free;
0544     eun->Deleted = 0;
0545 
0546     /* Now, the cache should be valid for the new block */
0547     part->bam_index = srcunit;
0548 
0549     return 0;
0550 } /* copy_erase_unit */
0551 
0552 /*======================================================================
0553 
0554     reclaim_block() picks a full erase unit and a transfer unit and
0555     then calls copy_erase_unit() to copy one to the other.  Then, it
0556     schedules an erase on the expired block.
0557 
0558     What's a good way to decide which transfer unit and which erase
0559     unit to use?  Beats me.  My way is to always pick the transfer
0560     unit with the fewest erases, and usually pick the data unit with
0561     the most deleted blocks.  But with a small probability, pick the
0562     oldest data unit instead.  This means that we generally postpone
0563     the next reclamation as long as possible, but shuffle static
0564     stuff around a bit for wear leveling.
0565 
0566 ======================================================================*/
0567 
0568 static int reclaim_block(partition_t *part)
0569 {
0570     uint16_t i, eun, xfer;
0571     uint32_t best;
0572     int queued, ret;
0573 
0574     pr_debug("ftl_cs: reclaiming space...\n");
0575     pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits);
0576     /* Pick the least erased transfer unit */
0577     best = 0xffffffff; xfer = 0xffff;
0578     do {
0579     queued = 0;
0580     for (i = 0; i < part->header.NumTransferUnits; i++) {
0581         int n=0;
0582         if (part->XferInfo[i].state == XFER_UNKNOWN) {
0583         pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i);
0584         n=1;
0585         erase_xfer(part, i);
0586         }
0587         if (part->XferInfo[i].state == XFER_ERASING) {
0588         pr_debug("XferInfo[%d].state == XFER_ERASING\n",i);
0589         n=1;
0590         queued = 1;
0591         }
0592         else if (part->XferInfo[i].state == XFER_ERASED) {
0593         pr_debug("XferInfo[%d].state == XFER_ERASED\n",i);
0594         n=1;
0595         prepare_xfer(part, i);
0596         }
0597         if (part->XferInfo[i].state == XFER_PREPARED) {
0598         pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i);
0599         n=1;
0600         if (part->XferInfo[i].EraseCount <= best) {
0601             best = part->XferInfo[i].EraseCount;
0602             xfer = i;
0603         }
0604         }
0605         if (!n)
0606             pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
0607 
0608     }
0609     if (xfer == 0xffff) {
0610         if (queued) {
0611         pr_debug("ftl_cs: waiting for transfer "
0612               "unit to be prepared...\n");
0613         mtd_sync(part->mbd.mtd);
0614         } else {
0615         static int ne = 0;
0616         if (++ne < 5)
0617             printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
0618                "suitable transfer units!\n");
0619         else
0620             pr_debug("ftl_cs: reclaim failed: no "
0621               "suitable transfer units!\n");
0622 
0623         return -EIO;
0624         }
0625     }
0626     } while (xfer == 0xffff);
0627 
0628     eun = 0;
0629     if ((jiffies % shuffle_freq) == 0) {
0630     pr_debug("ftl_cs: recycling freshest block...\n");
0631     best = 0xffffffff;
0632     for (i = 0; i < part->DataUnits; i++)
0633         if (part->EUNInfo[i].EraseCount <= best) {
0634         best = part->EUNInfo[i].EraseCount;
0635         eun = i;
0636         }
0637     } else {
0638     best = 0;
0639     for (i = 0; i < part->DataUnits; i++)
0640         if (part->EUNInfo[i].Deleted >= best) {
0641         best = part->EUNInfo[i].Deleted;
0642         eun = i;
0643         }
0644     if (best == 0) {
0645         static int ne = 0;
0646         if (++ne < 5)
0647         printk(KERN_NOTICE "ftl_cs: reclaim failed: "
0648                "no free blocks!\n");
0649         else
0650         pr_debug("ftl_cs: reclaim failed: "
0651                "no free blocks!\n");
0652 
0653         return -EIO;
0654     }
0655     }
0656     ret = copy_erase_unit(part, eun, xfer);
0657     if (!ret)
0658     erase_xfer(part, xfer);
0659     else
0660     printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
0661     return ret;
0662 } /* reclaim_block */
0663 
0664 /*======================================================================
0665 
0666     Find_free() searches for a free block.  If necessary, it updates
0667     the BAM cache for the erase unit containing the free block.  It
0668     returns the block index -- the erase unit is just the currently
0669     cached unit.  If there are no free blocks, it returns 0 -- this
0670     is never a valid data block because it contains the header.
0671 
0672 ======================================================================*/
0673 
0674 #ifdef PSYCHO_DEBUG
0675 static void dump_lists(partition_t *part)
0676 {
0677     int i;
0678     printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
0679     for (i = 0; i < part->DataUnits; i++)
0680     printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
0681            "%d deleted\n", i,
0682            part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
0683            part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
0684 }
0685 #endif
0686 
0687 static uint32_t find_free(partition_t *part)
0688 {
0689     uint16_t stop, eun;
0690     uint32_t blk;
0691     size_t retlen;
0692     int ret;
0693 
0694     /* Find an erase unit with some free space */
0695     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
0696     eun = stop;
0697     do {
0698     if (part->EUNInfo[eun].Free != 0) break;
0699     /* Wrap around at end of table */
0700     if (++eun == part->DataUnits) eun = 0;
0701     } while (eun != stop);
0702 
0703     if (part->EUNInfo[eun].Free == 0)
0704     return 0;
0705 
0706     /* Is this unit's BAM cached? */
0707     if (eun != part->bam_index) {
0708     /* Invalidate cache */
0709     part->bam_index = 0xffff;
0710 
0711     ret = mtd_read(part->mbd.mtd,
0712                        part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
0713                        part->BlocksPerUnit * sizeof(uint32_t),
0714                        &retlen,
0715                        (u_char *)(part->bam_cache));
0716 
0717     if (ret) {
0718         printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
0719         return 0;
0720     }
0721     part->bam_index = eun;
0722     }
0723 
0724     /* Find a free block */
0725     for (blk = 0; blk < part->BlocksPerUnit; blk++)
0726     if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
0727     if (blk == part->BlocksPerUnit) {
0728 #ifdef PSYCHO_DEBUG
0729     static int ne = 0;
0730     if (++ne == 1)
0731         dump_lists(part);
0732 #endif
0733     printk(KERN_NOTICE "ftl_cs: bad free list!\n");
0734     return 0;
0735     }
0736     pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun);
0737     return blk;
0738 
0739 } /* find_free */
0740 
0741 
0742 /*======================================================================
0743 
0744     Read a series of sectors from an FTL partition.
0745 
0746 ======================================================================*/
0747 
0748 static int ftl_read(partition_t *part, caddr_t buffer,
0749             u_long sector, u_long nblocks)
0750 {
0751     uint32_t log_addr, bsize;
0752     u_long i;
0753     int ret;
0754     size_t offset, retlen;
0755 
0756     pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
0757       part, sector, nblocks);
0758     if (!(part->state & FTL_FORMATTED)) {
0759     printk(KERN_NOTICE "ftl_cs: bad partition\n");
0760     return -EIO;
0761     }
0762     bsize = 1 << part->header.EraseUnitSize;
0763 
0764     for (i = 0; i < nblocks; i++) {
0765     if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
0766         printk(KERN_NOTICE "ftl_cs: bad read offset\n");
0767         return -EIO;
0768     }
0769     log_addr = part->VirtualBlockMap[sector+i];
0770     if (log_addr == 0xffffffff)
0771         memset(buffer, 0, SECTOR_SIZE);
0772     else {
0773         offset = (part->EUNInfo[log_addr / bsize].Offset
0774               + (log_addr % bsize));
0775         ret = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
0776                            (u_char *)buffer);
0777 
0778         if (ret) {
0779         printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
0780         return ret;
0781         }
0782     }
0783     buffer += SECTOR_SIZE;
0784     }
0785     return 0;
0786 } /* ftl_read */
0787 
0788 /*======================================================================
0789 
0790     Write a series of sectors to an FTL partition
0791 
0792 ======================================================================*/
0793 
0794 static int set_bam_entry(partition_t *part, uint32_t log_addr,
0795              uint32_t virt_addr)
0796 {
0797     uint32_t bsize, blk, le_virt_addr;
0798 #ifdef PSYCHO_DEBUG
0799     uint32_t old_addr;
0800 #endif
0801     uint16_t eun;
0802     int ret;
0803     size_t retlen, offset;
0804 
0805     pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
0806       part, log_addr, virt_addr);
0807     bsize = 1 << part->header.EraseUnitSize;
0808     eun = log_addr / bsize;
0809     blk = (log_addr % bsize) / SECTOR_SIZE;
0810     offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
0811           le32_to_cpu(part->header.BAMOffset));
0812 
0813 #ifdef PSYCHO_DEBUG
0814     ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
0815                    (u_char *)&old_addr);
0816     if (ret) {
0817     printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
0818     return ret;
0819     }
0820     old_addr = le32_to_cpu(old_addr);
0821 
0822     if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
0823     ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
0824     (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
0825     static int ne = 0;
0826     if (++ne < 5) {
0827         printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
0828         printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"
0829            ", new = 0x%x\n", log_addr, old_addr, virt_addr);
0830     }
0831     return -EIO;
0832     }
0833 #endif
0834     le_virt_addr = cpu_to_le32(virt_addr);
0835     if (part->bam_index == eun) {
0836 #ifdef PSYCHO_DEBUG
0837     if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
0838         static int ne = 0;
0839         if (++ne < 5) {
0840         printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
0841                "inconsistency!\n");
0842         printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"
0843                " = 0x%x\n",
0844                le32_to_cpu(part->bam_cache[blk]), old_addr);
0845         }
0846         return -EIO;
0847     }
0848 #endif
0849     part->bam_cache[blk] = le_virt_addr;
0850     }
0851     ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
0852                     (u_char *)&le_virt_addr);
0853 
0854     if (ret) {
0855     printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
0856     printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",
0857            log_addr, virt_addr);
0858     }
0859     return ret;
0860 } /* set_bam_entry */
0861 
0862 static int ftl_write(partition_t *part, caddr_t buffer,
0863              u_long sector, u_long nblocks)
0864 {
0865     uint32_t bsize, log_addr, virt_addr, old_addr, blk;
0866     u_long i;
0867     int ret;
0868     size_t retlen, offset;
0869 
0870     pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
0871       part, sector, nblocks);
0872     if (!(part->state & FTL_FORMATTED)) {
0873     printk(KERN_NOTICE "ftl_cs: bad partition\n");
0874     return -EIO;
0875     }
0876     /* See if we need to reclaim space, before we start */
0877     while (part->FreeTotal < nblocks) {
0878     ret = reclaim_block(part);
0879     if (ret)
0880         return ret;
0881     }
0882 
0883     bsize = 1 << part->header.EraseUnitSize;
0884 
0885     virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
0886     for (i = 0; i < nblocks; i++) {
0887     if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
0888         printk(KERN_NOTICE "ftl_cs: bad write offset\n");
0889         return -EIO;
0890     }
0891 
0892     /* Grab a free block */
0893     blk = find_free(part);
0894     if (blk == 0) {
0895         static int ne = 0;
0896         if (++ne < 5)
0897         printk(KERN_NOTICE "ftl_cs: internal error: "
0898                "no free blocks!\n");
0899         return -ENOSPC;
0900     }
0901 
0902     /* Tag the BAM entry, and write the new block */
0903     log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
0904     part->EUNInfo[part->bam_index].Free--;
0905     part->FreeTotal--;
0906     if (set_bam_entry(part, log_addr, 0xfffffffe))
0907         return -EIO;
0908     part->EUNInfo[part->bam_index].Deleted++;
0909     offset = (part->EUNInfo[part->bam_index].Offset +
0910               blk * SECTOR_SIZE);
0911     ret = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer);
0912 
0913     if (ret) {
0914         printk(KERN_NOTICE "ftl_cs: block write failed!\n");
0915         printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
0916            " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
0917            offset);
0918         return -EIO;
0919     }
0920 
0921     /* Only delete the old entry when the new entry is ready */
0922     old_addr = part->VirtualBlockMap[sector+i];
0923     if (old_addr != 0xffffffff) {
0924         part->VirtualBlockMap[sector+i] = 0xffffffff;
0925         part->EUNInfo[old_addr/bsize].Deleted++;
0926         if (set_bam_entry(part, old_addr, 0))
0927         return -EIO;
0928     }
0929 
0930     /* Finally, set up the new pointers */
0931     if (set_bam_entry(part, log_addr, virt_addr))
0932         return -EIO;
0933     part->VirtualBlockMap[sector+i] = log_addr;
0934     part->EUNInfo[part->bam_index].Deleted--;
0935 
0936     buffer += SECTOR_SIZE;
0937     virt_addr += SECTOR_SIZE;
0938     }
0939     return 0;
0940 } /* ftl_write */
0941 
0942 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
0943 {
0944     partition_t *part = (void *)dev;
0945     u_long sect;
0946 
0947     /* Sort of arbitrary: round size down to 4KiB boundary */
0948     sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
0949 
0950     geo->heads = 1;
0951     geo->sectors = 8;
0952     geo->cylinders = sect >> 3;
0953 
0954     return 0;
0955 }
0956 
0957 static int ftl_readsect(struct mtd_blktrans_dev *dev,
0958                   unsigned long block, char *buf)
0959 {
0960     return ftl_read((void *)dev, buf, block, 1);
0961 }
0962 
0963 static int ftl_writesect(struct mtd_blktrans_dev *dev,
0964                   unsigned long block, char *buf)
0965 {
0966     return ftl_write((void *)dev, buf, block, 1);
0967 }
0968 
0969 static int ftl_discardsect(struct mtd_blktrans_dev *dev,
0970                unsigned long sector, unsigned nr_sects)
0971 {
0972     partition_t *part = (void *)dev;
0973     uint32_t bsize = 1 << part->header.EraseUnitSize;
0974 
0975     pr_debug("FTL erase sector %ld for %d sectors\n",
0976           sector, nr_sects);
0977 
0978     while (nr_sects) {
0979         uint32_t old_addr = part->VirtualBlockMap[sector];
0980         if (old_addr != 0xffffffff) {
0981             part->VirtualBlockMap[sector] = 0xffffffff;
0982             part->EUNInfo[old_addr/bsize].Deleted++;
0983             if (set_bam_entry(part, old_addr, 0))
0984                 return -EIO;
0985         }
0986         nr_sects--;
0987         sector++;
0988     }
0989 
0990     return 0;
0991 }
0992 /*====================================================================*/
0993 
0994 static void ftl_freepart(partition_t *part)
0995 {
0996     vfree(part->VirtualBlockMap);
0997     part->VirtualBlockMap = NULL;
0998     kfree(part->EUNInfo);
0999     part->EUNInfo = NULL;
1000     kfree(part->XferInfo);
1001     part->XferInfo = NULL;
1002     kfree(part->bam_cache);
1003     part->bam_cache = NULL;
1004 } /* ftl_freepart */
1005 
1006 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1007 {
1008     partition_t *partition;
1009 
1010     partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1011 
1012     if (!partition) {
1013         printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1014                mtd->name);
1015         return;
1016     }
1017 
1018     partition->mbd.mtd = mtd;
1019 
1020     if ((scan_header(partition) == 0) &&
1021         (build_maps(partition) == 0)) {
1022 
1023         partition->state = FTL_FORMATTED;
1024 #ifdef PCMCIA_DEBUG
1025         printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1026                le32_to_cpu(partition->header.FormattedSize) >> 10);
1027 #endif
1028         partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1029 
1030         partition->mbd.tr = tr;
1031         partition->mbd.devnum = -1;
1032         if (!add_mtd_blktrans_dev(&partition->mbd))
1033             return;
1034     }
1035 
1036     kfree(partition);
1037 }
1038 
1039 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1040 {
1041     del_mtd_blktrans_dev(dev);
1042     ftl_freepart((partition_t *)dev);
1043 }
1044 
1045 static struct mtd_blktrans_ops ftl_tr = {
1046     .name       = "ftl",
1047     .major      = FTL_MAJOR,
1048     .part_bits  = PART_BITS,
1049     .blksize    = SECTOR_SIZE,
1050     .readsect   = ftl_readsect,
1051     .writesect  = ftl_writesect,
1052     .discard    = ftl_discardsect,
1053     .getgeo     = ftl_getgeo,
1054     .add_mtd    = ftl_add_mtd,
1055     .remove_dev = ftl_remove_dev,
1056     .owner      = THIS_MODULE,
1057 };
1058 
1059 module_mtd_blktrans(ftl_tr);
1060 
1061 MODULE_LICENSE("Dual MPL/GPL");
1062 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
1063 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");