1179187Sjb/* This version ported to the Linux-MTD system by dwmw2@infradead.org 2179187Sjb * 3179187Sjb * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> 4179187Sjb * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups 5179187Sjb * 6179187Sjb * Based on: 7179187Sjb */ 8179187Sjb/*====================================================================== 9179187Sjb 10179187Sjb A Flash Translation Layer memory card driver 11179187Sjb 12179187Sjb This driver implements a disk-like block device driver with an 13179187Sjb apparent block size of 512 bytes for flash memory cards. 14179187Sjb 15179187Sjb ftl_cs.c 1.62 2000/02/01 00:59:04 16179187Sjb 17179187Sjb The contents of this file are subject to the Mozilla Public 18179187Sjb License Version 1.1 (the "License"); you may not use this file 19179187Sjb except in compliance with the License. You may obtain a copy of 20179187Sjb the License at http://www.mozilla.org/MPL/ 21179187Sjb 22179187Sjb Software distributed under the License is distributed on an "AS 23179187Sjb IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 24179187Sjb implied. See the License for the specific language governing 25179187Sjb rights and limitations under the License. 26179187Sjb 27179187Sjb The initial developer of the original code is David A. Hinds 28179187Sjb <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 29179187Sjb are Copyright �� 1999 David A. Hinds. All Rights Reserved. 30179187Sjb 31179187Sjb Alternatively, the contents of this file may be used under the 32179187Sjb terms of the GNU General Public License version 2 (the "GPL"), in 33179187Sjb which case the provisions of the GPL are applicable instead of the 34179187Sjb above. If you wish to allow the use of your version of this file 35179187Sjb only under the terms of the GPL and not to allow others to use 36179187Sjb your version of this file under the MPL, indicate your decision 37179187Sjb by deleting the provisions above and replace them with the notice 38179187Sjb and other provisions required by the GPL. If you do not delete 39179187Sjb the provisions above, a recipient may use your version of this 40179187Sjb file under either the MPL or the GPL. 41179187Sjb 42179187Sjb LEGAL NOTE: The FTL format is patented by M-Systems. They have 43179187Sjb granted a license for its use with PCMCIA devices: 44179187Sjb 45179187Sjb "M-Systems grants a royalty-free, non-exclusive license under 46179187Sjb any presently existing M-Systems intellectual property rights 47179187Sjb necessary for the design and development of FTL-compatible 48179187Sjb drivers, file systems and utilities using the data formats with 49179187Sjb PCMCIA PC Cards as described in the PCMCIA Flash Translation 50179187Sjb Layer (FTL) Specification." 51179187Sjb 52179187Sjb Use of the FTL format for non-PCMCIA applications may be an 53179187Sjb infringement of these patents. For additional information, 54179187Sjb contact M-Systems directly. M-Systems since acquired by Sandisk. 55179187Sjb 56179187Sjb======================================================================*/ 57179187Sjb#include <linux/mtd/blktrans.h> 58179187Sjb#include <linux/module.h> 59179187Sjb#include <linux/mtd/mtd.h> 60179187Sjb/*#define PSYCHO_DEBUG */ 61179187Sjb 62179187Sjb#include <linux/kernel.h> 63179187Sjb#include <linux/ptrace.h> 64179187Sjb#include <linux/slab.h> 65179187Sjb#include <linux/string.h> 66179187Sjb#include <linux/timer.h> 67179187Sjb#include <linux/major.h> 68179187Sjb#include <linux/fs.h> 69179187Sjb#include <linux/init.h> 70179187Sjb#include <linux/hdreg.h> 71179187Sjb#include <linux/vmalloc.h> 72179187Sjb#include <linux/blkpg.h> 73179187Sjb#include <linux/uaccess.h> 74179187Sjb 75179187Sjb#include <linux/mtd/ftl.h> 76179187Sjb 77179187Sjb/*====================================================================*/ 78179187Sjb 79179187Sjb/* Parameters that can be set with 'insmod' */ 80179187Sjbstatic int shuffle_freq = 50; 81179187Sjbmodule_param(shuffle_freq, int, 0); 82179187Sjb 83179187Sjb/*====================================================================*/ 84179187Sjb 85179187Sjb/* Major device # for FTL device */ 86179187Sjb#ifndef FTL_MAJOR 87179187Sjb#define FTL_MAJOR 44 88179187Sjb#endif 89179187Sjb 90179187Sjb 91179187Sjb/*====================================================================*/ 92179187Sjb 93179187Sjb/* Maximum number of separate memory devices we'll allow */ 94179187Sjb#define MAX_DEV 4 95179187Sjb 96179187Sjb/* Maximum number of regions per device */ 97179187Sjb#define MAX_REGION 4 98179187Sjb 99179187Sjb/* Maximum number of partitions in an FTL region */ 100179187Sjb#define PART_BITS 4 101179187Sjb 102179187Sjb/* Maximum number of outstanding erase requests per socket */ 103179187Sjb#define MAX_ERASE 8 104179187Sjb 105179187Sjb/* Sector size -- shouldn't need to change */ 106179187Sjb#define SECTOR_SIZE 512 107179187Sjb 108179187Sjb 109179187Sjb/* Each memory region corresponds to a minor device */ 110179187Sjbtypedef struct partition_t { 111179187Sjb struct mtd_blktrans_dev mbd; 112179187Sjb uint32_t state; 113179187Sjb uint32_t *VirtualBlockMap; 114179187Sjb uint32_t FreeTotal; 115179187Sjb struct eun_info_t { 116179187Sjb uint32_t Offset; 117179187Sjb uint32_t EraseCount; 118179187Sjb uint32_t Free; 119179187Sjb uint32_t Deleted; 120179187Sjb } *EUNInfo; 121179187Sjb struct xfer_info_t { 122179187Sjb uint32_t Offset; 123179187Sjb uint32_t EraseCount; 124179187Sjb uint16_t state; 125179187Sjb } *XferInfo; 126179187Sjb uint16_t bam_index; 127179187Sjb uint32_t *bam_cache; 128179187Sjb uint16_t DataUnits; 129179187Sjb uint32_t BlocksPerUnit; 130179187Sjb erase_unit_header_t header; 131179187Sjb} partition_t; 132179187Sjb 133179187Sjb/* Partition state flags */ 134179187Sjb#define FTL_FORMATTED 0x01 135179187Sjb 136179187Sjb/* Transfer unit states */ 137179187Sjb#define XFER_UNKNOWN 0x00 138179187Sjb#define XFER_ERASING 0x01 139179187Sjb#define XFER_ERASED 0x02 140179187Sjb#define XFER_PREPARED 0x03 141179187Sjb#define XFER_FAILED 0x04 142179187Sjb 143179187Sjb/*====================================================================== 144179187Sjb 145179187Sjb Scan_header() checks to see if a memory region contains an FTL 146179187Sjb partition. build_maps() reads all the erase unit headers, builds 147179187Sjb the erase unit map, and then builds the virtual page map. 148179187Sjb 149179187Sjb======================================================================*/ 150179187Sjb 151179187Sjbstatic int scan_header(partition_t *part) 152179187Sjb{ 153179187Sjb erase_unit_header_t header; 154179187Sjb loff_t offset, max_offset; 155179187Sjb size_t ret; 156179187Sjb int err; 157179187Sjb part->header.FormattedSize = 0; 158179187Sjb max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size; 159179187Sjb /* Search first megabyte for a valid FTL header */ 160179187Sjb for (offset = 0; 161179187Sjb (offset + sizeof(header)) < max_offset; 162179187Sjb offset += part->mbd.mtd->erasesize ? : 0x2000) { 163179187Sjb 164179187Sjb err = mtd_read(part->mbd.mtd, offset, sizeof(header), &ret, 165179187Sjb (unsigned char *)&header); 166179187Sjb 167179187Sjb if (err) 168179187Sjb return err; 169179187Sjb 170179187Sjb if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break; 171179187Sjb } 172179187Sjb 173179187Sjb if (offset == max_offset) { 174179187Sjb printk(KERN_NOTICE "ftl_cs: FTL header not found.\n"); 175179187Sjb return -ENOENT; 176179187Sjb } 177179187Sjb if (header.BlockSize != 9 || 178179187Sjb (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) || 179179187Sjb (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) { 180179187Sjb printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n"); 181179187Sjb return -1; 182179187Sjb } 183179187Sjb if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) { 184179187Sjb printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n", 185179187Sjb 1 << header.EraseUnitSize,part->mbd.mtd->erasesize); 186179187Sjb return -1; 187179187Sjb } 188179187Sjb part->header = header; 189179187Sjb return 0; 190179187Sjb} 191179187Sjb 192179187Sjbstatic int build_maps(partition_t *part) 193179187Sjb{ 194179187Sjb erase_unit_header_t header; 195252430Skaiw uint16_t xvalid, xtrans, i; 196179187Sjb unsigned blocks, j; 197179187Sjb int hdr_ok, ret = -1; 198179187Sjb ssize_t retval; 199179187Sjb loff_t offset; 200179187Sjb 201179187Sjb /* Set up erase unit maps */ 202179187Sjb part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) - 203179187Sjb part->header.NumTransferUnits; 204179187Sjb part->EUNInfo = kmalloc_array(part->DataUnits, sizeof(struct eun_info_t), 205179187Sjb GFP_KERNEL); 206179187Sjb if (!part->EUNInfo) 207179187Sjb goto out; 208179187Sjb for (i = 0; i < part->DataUnits; i++) 209179187Sjb part->EUNInfo[i].Offset = 0xffffffff; 210179187Sjb part->XferInfo = 211179187Sjb kmalloc_array(part->header.NumTransferUnits, 212179187Sjb sizeof(struct xfer_info_t), 213179187Sjb GFP_KERNEL); 214179187Sjb if (!part->XferInfo) 215179187Sjb goto out_EUNInfo; 216179187Sjb 217179187Sjb xvalid = xtrans = 0; 218179187Sjb for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { 219179187Sjb offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) 220179187Sjb << part->header.EraseUnitSize); 221179187Sjb ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval, 222179187Sjb (unsigned char *)&header); 223179187Sjb 224179187Sjb if (ret) 225179187Sjb goto out_XferInfo; 226179187Sjb 227179187Sjb ret = -1; 228179187Sjb /* Is this a transfer partition? */ 229179187Sjb hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0); 230179187Sjb if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) && 231179187Sjb (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) { 232179187Sjb part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset; 233179187Sjb part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount = 234179187Sjb le32_to_cpu(header.EraseCount); 235179187Sjb xvalid++; 236179187Sjb } else { 237179187Sjb if (xtrans == part->header.NumTransferUnits) { 238179187Sjb printk(KERN_NOTICE "ftl_cs: format error: too many " 239179187Sjb "transfer units!\n"); 240179187Sjb goto out_XferInfo; 241179187Sjb } 242179187Sjb if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) { 243179187Sjb part->XferInfo[xtrans].state = XFER_PREPARED; 244179187Sjb part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount); 245179187Sjb } else { 246179187Sjb part->XferInfo[xtrans].state = XFER_UNKNOWN; 247179187Sjb /* Pick anything reasonable for the erase count */ 248179187Sjb part->XferInfo[xtrans].EraseCount = 249179187Sjb le32_to_cpu(part->header.EraseCount); 250179187Sjb } 251179187Sjb part->XferInfo[xtrans].Offset = offset; 252179187Sjb xtrans++; 253179187Sjb } 254179187Sjb } 255179187Sjb /* Check for format trouble */ 256179187Sjb header = part->header; 257179187Sjb if ((xtrans != header.NumTransferUnits) || 258179187Sjb (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) { 259179187Sjb printk(KERN_NOTICE "ftl_cs: format error: erase units " 260179187Sjb "don't add up!\n"); 261179187Sjb goto out_XferInfo; 262179187Sjb } 263179187Sjb 264179187Sjb /* Set up virtual page map */ 265179187Sjb blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; 266179187Sjb part->VirtualBlockMap = vmalloc(array_size(blocks, sizeof(uint32_t))); 267179187Sjb if (!part->VirtualBlockMap) 268179187Sjb goto out_XferInfo; 269179187Sjb 270179187Sjb memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t)); 271179187Sjb part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize; 272179187Sjb 273179187Sjb part->bam_cache = kmalloc_array(part->BlocksPerUnit, sizeof(uint32_t), 274179187Sjb GFP_KERNEL); 275179187Sjb if (!part->bam_cache) 276179187Sjb goto out_VirtualBlockMap; 277179187Sjb 278179187Sjb part->bam_index = 0xffff; 279179187Sjb part->FreeTotal = 0; 280179187Sjb 281179187Sjb for (i = 0; i < part->DataUnits; i++) { 282179187Sjb part->EUNInfo[i].Free = 0; 283179187Sjb part->EUNInfo[i].Deleted = 0; 284179187Sjb offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); 285179187Sjb 286179187Sjb ret = mtd_read(part->mbd.mtd, offset, 287179187Sjb part->BlocksPerUnit * sizeof(uint32_t), &retval, 288179187Sjb (unsigned char *)part->bam_cache); 289179187Sjb 290179187Sjb if (ret) 291179187Sjb goto out_bam_cache; 292179187Sjb 293179187Sjb for (j = 0; j < part->BlocksPerUnit; j++) { 294179187Sjb if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) { 295179187Sjb part->EUNInfo[i].Free++; 296179187Sjb part->FreeTotal++; 297179187Sjb } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) && 298179187Sjb (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks)) 299179187Sjb part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] = 300179187Sjb (i << header.EraseUnitSize) + (j << header.BlockSize); 301179187Sjb else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j]))) 302179187Sjb part->EUNInfo[i].Deleted++; 303179187Sjb } 304179187Sjb } 305179187Sjb 306179187Sjb ret = 0; 307179187Sjb goto out; 308179187Sjb 309179187Sjbout_bam_cache: 310179187Sjb kfree(part->bam_cache); 311179187Sjbout_VirtualBlockMap: 312179187Sjb vfree(part->VirtualBlockMap); 313179187Sjbout_XferInfo: 314179187Sjb kfree(part->XferInfo); 315179187Sjbout_EUNInfo: 316179187Sjb kfree(part->EUNInfo); 317179187Sjbout: 318179187Sjb return ret; 319179187Sjb} /* build_maps */ 320179187Sjb 321179187Sjb/*====================================================================== 322179187Sjb 323179187Sjb Erase_xfer() schedules an asynchronous erase operation for a 324179187Sjb transfer unit. 325179187Sjb 326179187Sjb======================================================================*/ 327179187Sjb 328179187Sjbstatic int erase_xfer(partition_t *part, 329179187Sjb uint16_t xfernum) 330179187Sjb{ 331179187Sjb int ret; 332179187Sjb struct xfer_info_t *xfer; 333179187Sjb struct erase_info *erase; 334179187Sjb 335179187Sjb xfer = &part->XferInfo[xfernum]; 336179187Sjb pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); 337179187Sjb xfer->state = XFER_ERASING; 338179187Sjb 339179187Sjb /* Is there a free erase slot? Always in MTD. */ 340179187Sjb 341179187Sjb 342179187Sjb erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL); 343179187Sjb if (!erase) 344179187Sjb return -ENOMEM; 345179187Sjb 346179187Sjb erase->addr = xfer->Offset; 347179187Sjb erase->len = 1 << part->header.EraseUnitSize; 348179187Sjb 349179187Sjb ret = mtd_erase(part->mbd.mtd, erase); 350179187Sjb if (!ret) { 351179187Sjb xfer->state = XFER_ERASED; 352179187Sjb xfer->EraseCount++; 353179187Sjb } else { 354179187Sjb xfer->state = XFER_FAILED; 355179187Sjb pr_notice("ftl_cs: erase failed: err = %d\n", ret); 356179187Sjb } 357179187Sjb 358179187Sjb kfree(erase); 359179187Sjb 360179187Sjb return ret; 361179187Sjb} /* erase_xfer */ 362179187Sjb 363179187Sjb/*====================================================================== 364179187Sjb 365179187Sjb Prepare_xfer() takes a freshly erased transfer unit and gives 366179187Sjb it an appropriate header. 367179187Sjb 368179187Sjb======================================================================*/ 369179187Sjb 370179187Sjbstatic int prepare_xfer(partition_t *part, int i) 371179187Sjb{ 372179187Sjb erase_unit_header_t header; 373179187Sjb struct xfer_info_t *xfer; 374179187Sjb int nbam, ret; 375179187Sjb uint32_t ctl; 376179187Sjb ssize_t retlen; 377179187Sjb loff_t offset; 378179187Sjb 379179187Sjb xfer = &part->XferInfo[i]; 380179187Sjb xfer->state = XFER_FAILED; 381179187Sjb 382179187Sjb pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); 383179187Sjb 384179187Sjb /* Write the transfer unit header */ 385179187Sjb header = part->header; 386179187Sjb header.LogicalEUN = cpu_to_le16(0xffff); 387179187Sjb header.EraseCount = cpu_to_le32(xfer->EraseCount); 388179187Sjb 389179187Sjb ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen, 390179187Sjb (u_char *)&header); 391179187Sjb 392179187Sjb if (ret) { 393179187Sjb return ret; 394179187Sjb } 395179187Sjb 396179187Sjb /* Write the BAM stub */ 397179187Sjb nbam = DIV_ROUND_UP(part->BlocksPerUnit * sizeof(uint32_t) + 398179187Sjb le32_to_cpu(part->header.BAMOffset), SECTOR_SIZE); 399239872Sdim 400239872Sdim offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset); 401239872Sdim ctl = cpu_to_le32(BLOCK_CONTROL); 402239872Sdim 403179187Sjb for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) { 404179187Sjb 405179187Sjb ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, 406179187Sjb (u_char *)&ctl); 407179187Sjb 408179187Sjb if (ret) 409179187Sjb return ret; 410179187Sjb } 411179187Sjb xfer->state = XFER_PREPARED; 412179187Sjb return 0; 413179187Sjb 414179187Sjb} /* prepare_xfer */ 415179187Sjb 416179187Sjb/*====================================================================== 417179187Sjb 418179187Sjb Copy_erase_unit() takes a full erase block and a transfer unit, 419179187Sjb copies everything to the transfer unit, then swaps the block 420179187Sjb pointers. 421179187Sjb 422179187Sjb All data blocks are copied to the corresponding blocks in the 423179187Sjb target unit, so the virtual block map does not need to be 424179187Sjb updated. 425179187Sjb 426179187Sjb======================================================================*/ 427179187Sjb 428179187Sjbstatic int copy_erase_unit(partition_t *part, uint16_t srcunit, 429179187Sjb uint16_t xferunit) 430179187Sjb{ 431179187Sjb u_char buf[SECTOR_SIZE]; 432179187Sjb struct eun_info_t *eun; 433179187Sjb struct xfer_info_t *xfer; 434179187Sjb uint32_t src, dest, free, i; 435179187Sjb uint16_t unit; 436179187Sjb int ret; 437179187Sjb ssize_t retlen; 438179187Sjb loff_t offset; 439179187Sjb uint16_t srcunitswap = cpu_to_le16(srcunit); 440179187Sjb 441179187Sjb eun = &part->EUNInfo[srcunit]; 442179187Sjb xfer = &part->XferInfo[xferunit]; 443179187Sjb pr_debug("ftl_cs: copying block 0x%x to 0x%x\n", 444179187Sjb eun->Offset, xfer->Offset); 445179187Sjb 446179187Sjb 447179187Sjb /* Read current BAM */ 448179187Sjb if (part->bam_index != srcunit) { 449179187Sjb 450179187Sjb offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); 451179187Sjb 452179187Sjb ret = mtd_read(part->mbd.mtd, offset, 453179187Sjb part->BlocksPerUnit * sizeof(uint32_t), &retlen, 454179187Sjb (u_char *)(part->bam_cache)); 455179187Sjb 456179187Sjb /* mark the cache bad, in case we get an error later */ 457179187Sjb part->bam_index = 0xffff; 458179187Sjb 459179187Sjb if (ret) { 460179187Sjb printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); 461179187Sjb return ret; 462179187Sjb } 463179187Sjb } 464179187Sjb 465179187Sjb /* Write the LogicalEUN for the transfer unit */ 466179187Sjb xfer->state = XFER_UNKNOWN; 467179187Sjb offset = xfer->Offset + 20; /* Bad! */ 468179187Sjb unit = cpu_to_le16(0x7fff); 469179187Sjb 470179187Sjb ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen, 471179187Sjb (u_char *)&unit); 472179187Sjb 473179187Sjb if (ret) { 474179187Sjb printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n"); 475179187Sjb return ret; 476179187Sjb } 477179187Sjb 478179187Sjb /* Copy all data blocks from source unit to transfer unit */ 479179187Sjb src = eun->Offset; dest = xfer->Offset; 480179187Sjb 481179187Sjb free = 0; 482179187Sjb ret = 0; 483179187Sjb for (i = 0; i < part->BlocksPerUnit; i++) { 484179187Sjb switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) { 485179187Sjb case BLOCK_CONTROL: 486179187Sjb /* This gets updated later */ 487179187Sjb break; 488179187Sjb case BLOCK_DATA: 489179187Sjb case BLOCK_REPLACEMENT: 490179187Sjb ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen, 491179187Sjb (u_char *)buf); 492179187Sjb if (ret) { 493179187Sjb printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n"); 494179187Sjb return ret; 495179187Sjb } 496179187Sjb 497179187Sjb 498179187Sjb ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen, 499179187Sjb (u_char *)buf); 500179187Sjb if (ret) { 501179187Sjb printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n"); 502179187Sjb return ret; 503179187Sjb } 504179187Sjb 505179187Sjb break; 506179187Sjb default: 507179187Sjb /* All other blocks must be free */ 508179187Sjb part->bam_cache[i] = cpu_to_le32(0xffffffff); 509179187Sjb free++; 510179187Sjb break; 511179187Sjb } 512179187Sjb src += SECTOR_SIZE; 513179187Sjb dest += SECTOR_SIZE; 514179187Sjb } 515179187Sjb 516179187Sjb /* Write the BAM to the transfer unit */ 517179187Sjb ret = mtd_write(part->mbd.mtd, 518179187Sjb xfer->Offset + le32_to_cpu(part->header.BAMOffset), 519179187Sjb part->BlocksPerUnit * sizeof(int32_t), 520179187Sjb &retlen, 521179187Sjb (u_char *)part->bam_cache); 522179187Sjb if (ret) { 523179187Sjb printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n"); 524179187Sjb return ret; 525179187Sjb } 526179187Sjb 527179187Sjb 528179187Sjb /* All clear? Then update the LogicalEUN again */ 529179187Sjb ret = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t), 530179187Sjb &retlen, (u_char *)&srcunitswap); 531179187Sjb 532179187Sjb if (ret) { 533179187Sjb printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n"); 534179187Sjb return ret; 535179187Sjb } 536179187Sjb 537179187Sjb 538179187Sjb /* Update the maps and usage stats*/ 539179187Sjb swap(xfer->EraseCount, eun->EraseCount); 540179187Sjb swap(xfer->Offset, eun->Offset); 541179187Sjb part->FreeTotal -= eun->Free; 542179187Sjb part->FreeTotal += free; 543179187Sjb eun->Free = free; 544179187Sjb eun->Deleted = 0; 545179187Sjb 546179187Sjb /* Now, the cache should be valid for the new block */ 547179187Sjb part->bam_index = srcunit; 548179187Sjb 549179187Sjb return 0; 550179187Sjb} /* copy_erase_unit */ 551179187Sjb 552179187Sjb/*====================================================================== 553179187Sjb 554241844Seadler reclaim_block() picks a full erase unit and a transfer unit and 555179187Sjb then calls copy_erase_unit() to copy one to the other. Then, it 556179187Sjb schedules an erase on the expired block. 557179187Sjb 558179187Sjb What's a good way to decide which transfer unit and which erase 559179187Sjb unit to use? Beats me. My way is to always pick the transfer 560179187Sjb unit with the fewest erases, and usually pick the data unit with 561179187Sjb the most deleted blocks. But with a small probability, pick the 562179187Sjb oldest data unit instead. This means that we generally postpone 563179187Sjb the next reclamation as long as possible, but shuffle static 564179187Sjb stuff around a bit for wear leveling. 565179187Sjb 566179187Sjb======================================================================*/ 567179187Sjb 568179187Sjbstatic int reclaim_block(partition_t *part) 569179187Sjb{ 570179187Sjb uint16_t i, eun, xfer; 571179187Sjb uint32_t best; 572179187Sjb int queued, ret; 573179187Sjb 574179187Sjb pr_debug("ftl_cs: reclaiming space...\n"); 575179187Sjb pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits); 576179187Sjb /* Pick the least erased transfer unit */ 577179187Sjb best = 0xffffffff; xfer = 0xffff; 578179187Sjb do { 579179187Sjb queued = 0; 580179187Sjb for (i = 0; i < part->header.NumTransferUnits; i++) { 581179187Sjb int n=0; 582179187Sjb if (part->XferInfo[i].state == XFER_UNKNOWN) { 583179187Sjb pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i); 584179187Sjb n=1; 585221569Sobrien erase_xfer(part, i); 586221569Sobrien } 587221569Sobrien if (part->XferInfo[i].state == XFER_ERASING) { 588179187Sjb pr_debug("XferInfo[%d].state == XFER_ERASING\n",i); 589179187Sjb n=1; 590179187Sjb queued = 1; 591179187Sjb } 592179187Sjb else if (part->XferInfo[i].state == XFER_ERASED) { 593179187Sjb pr_debug("XferInfo[%d].state == XFER_ERASED\n",i); 594179187Sjb n=1; 595179187Sjb prepare_xfer(part, i); 596179187Sjb } 597179187Sjb if (part->XferInfo[i].state == XFER_PREPARED) { 598179187Sjb pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i); 599179187Sjb n=1; 600179187Sjb if (part->XferInfo[i].EraseCount <= best) { 601179187Sjb best = part->XferInfo[i].EraseCount; 602179187Sjb xfer = i; 603179187Sjb } 604179187Sjb } 605179187Sjb if (!n) 606179187Sjb pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); 607179187Sjb 608179187Sjb } 609179187Sjb if (xfer == 0xffff) { 610179187Sjb if (queued) { 611179187Sjb pr_debug("ftl_cs: waiting for transfer " 612179187Sjb "unit to be prepared...\n"); 613179187Sjb mtd_sync(part->mbd.mtd); 614179187Sjb } else { 615179187Sjb static int ne = 0; 616179187Sjb if (++ne < 5) 617179187Sjb printk(KERN_NOTICE "ftl_cs: reclaim failed: no " 618179187Sjb "suitable transfer units!\n"); 619179187Sjb else 620179187Sjb pr_debug("ftl_cs: reclaim failed: no " 621179187Sjb "suitable transfer units!\n"); 622179187Sjb 623179187Sjb return -EIO; 624179187Sjb } 625179187Sjb } 626179187Sjb } while (xfer == 0xffff); 627179187Sjb 628179187Sjb eun = 0; 629179187Sjb if ((jiffies % shuffle_freq) == 0) { 630179187Sjb pr_debug("ftl_cs: recycling freshest block...\n"); 631179187Sjb best = 0xffffffff; 632179187Sjb for (i = 0; i < part->DataUnits; i++) 633179187Sjb if (part->EUNInfo[i].EraseCount <= best) { 634179187Sjb best = part->EUNInfo[i].EraseCount; 635179187Sjb eun = i; 636179187Sjb } 637179187Sjb } else { 638179187Sjb best = 0; 639179187Sjb for (i = 0; i < part->DataUnits; i++) 640179187Sjb if (part->EUNInfo[i].Deleted >= best) { 641179187Sjb best = part->EUNInfo[i].Deleted; 642179187Sjb eun = i; 643179187Sjb } 644179187Sjb if (best == 0) { 645179187Sjb static int ne = 0; 646179187Sjb if (++ne < 5) 647179187Sjb printk(KERN_NOTICE "ftl_cs: reclaim failed: " 648179187Sjb "no free blocks!\n"); 649179187Sjb else 650179187Sjb pr_debug("ftl_cs: reclaim failed: " 651179187Sjb "no free blocks!\n"); 652179187Sjb 653179187Sjb return -EIO; 654179187Sjb } 655179187Sjb } 656179187Sjb ret = copy_erase_unit(part, eun, xfer); 657179187Sjb if (!ret) 658179187Sjb erase_xfer(part, xfer); 659179187Sjb else 660179187Sjb printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n"); 661179187Sjb return ret; 662179187Sjb} /* reclaim_block */ 663179187Sjb 664179187Sjb/*====================================================================== 665179187Sjb 666179187Sjb Find_free() searches for a free block. If necessary, it updates 667179187Sjb the BAM cache for the erase unit containing the free block. It 668179187Sjb returns the block index -- the erase unit is just the currently 669179187Sjb cached unit. If there are no free blocks, it returns 0 -- this 670179187Sjb is never a valid data block because it contains the header. 671179187Sjb 672179187Sjb======================================================================*/ 673179187Sjb 674179187Sjb#ifdef PSYCHO_DEBUG 675179187Sjbstatic void dump_lists(partition_t *part) 676179187Sjb{ 677179187Sjb int i; 678179187Sjb printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal); 679179187Sjb for (i = 0; i < part->DataUnits; i++) 680179187Sjb printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, " 681179187Sjb "%d deleted\n", i, 682179187Sjb part->EUNInfo[i].Offset >> part->header.EraseUnitSize, 683179187Sjb part->EUNInfo[i].Free, part->EUNInfo[i].Deleted); 684179187Sjb} 685179187Sjb#endif 686179187Sjb 687179187Sjbstatic uint32_t find_free(partition_t *part) 688179187Sjb{ 689179187Sjb uint16_t stop, eun; 690179187Sjb uint32_t blk; 691179187Sjb size_t retlen; 692179187Sjb int ret; 693179187Sjb 694179187Sjb /* Find an erase unit with some free space */ 695179187Sjb stop = (part->bam_index == 0xffff) ? 0 : part->bam_index; 696221569Sobrien eun = stop; 697179187Sjb do { 698179187Sjb if (part->EUNInfo[eun].Free != 0) break; 699179187Sjb /* Wrap around at end of table */ 700179187Sjb if (++eun == part->DataUnits) eun = 0; 701179187Sjb } while (eun != stop); 702179187Sjb 703179187Sjb if (part->EUNInfo[eun].Free == 0) 704179187Sjb return 0; 705179187Sjb 706179187Sjb /* Is this unit's BAM cached? */ 707179187Sjb if (eun != part->bam_index) { 708179187Sjb /* Invalidate cache */ 709179187Sjb part->bam_index = 0xffff; 710179187Sjb 711179187Sjb ret = mtd_read(part->mbd.mtd, 712179187Sjb part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), 713179187Sjb part->BlocksPerUnit * sizeof(uint32_t), 714179187Sjb &retlen, 715179187Sjb (u_char *)(part->bam_cache)); 716179187Sjb 717179187Sjb if (ret) { 718179187Sjb printk(KERN_WARNING"ftl: Error reading BAM in find_free\n"); 719179187Sjb return 0; 720179187Sjb } 721179187Sjb part->bam_index = eun; 722179187Sjb } 723179187Sjb 724179187Sjb /* Find a free block */ 725179187Sjb for (blk = 0; blk < part->BlocksPerUnit; blk++) 726179187Sjb if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break; 727179187Sjb if (blk == part->BlocksPerUnit) { 728179187Sjb#ifdef PSYCHO_DEBUG 729179187Sjb static int ne = 0; 730179187Sjb if (++ne == 1) 731179187Sjb dump_lists(part); 732179187Sjb#endif 733179187Sjb printk(KERN_NOTICE "ftl_cs: bad free list!\n"); 734179187Sjb return 0; 735179187Sjb } 736179187Sjb pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun); 737179187Sjb return blk; 738179187Sjb 739179187Sjb} /* find_free */ 740179187Sjb 741179187Sjb 742179187Sjb/*====================================================================== 743179187Sjb 744179187Sjb Read a series of sectors from an FTL partition. 745179187Sjb 746179187Sjb======================================================================*/ 747179187Sjb 748179187Sjbstatic int ftl_read(partition_t *part, caddr_t buffer, 749179187Sjb u_long sector, u_long nblocks) 750179187Sjb{ 751179187Sjb uint32_t log_addr, bsize; 752179187Sjb u_long i; 753179187Sjb int ret; 754179187Sjb size_t offset, retlen; 755179187Sjb 756179187Sjb pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", 757 part, sector, nblocks); 758 if (!(part->state & FTL_FORMATTED)) { 759 printk(KERN_NOTICE "ftl_cs: bad partition\n"); 760 return -EIO; 761 } 762 bsize = 1 << part->header.EraseUnitSize; 763 764 for (i = 0; i < nblocks; i++) { 765 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) { 766 printk(KERN_NOTICE "ftl_cs: bad read offset\n"); 767 return -EIO; 768 } 769 log_addr = part->VirtualBlockMap[sector+i]; 770 if (log_addr == 0xffffffff) 771 memset(buffer, 0, SECTOR_SIZE); 772 else { 773 offset = (part->EUNInfo[log_addr / bsize].Offset 774 + (log_addr % bsize)); 775 ret = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, 776 (u_char *)buffer); 777 778 if (ret) { 779 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n"); 780 return ret; 781 } 782 } 783 buffer += SECTOR_SIZE; 784 } 785 return 0; 786} /* ftl_read */ 787 788/*====================================================================== 789 790 Write a series of sectors to an FTL partition 791 792======================================================================*/ 793 794static int set_bam_entry(partition_t *part, uint32_t log_addr, 795 uint32_t virt_addr) 796{ 797 uint32_t bsize, blk, le_virt_addr; 798#ifdef PSYCHO_DEBUG 799 uint32_t old_addr; 800#endif 801 uint16_t eun; 802 int ret; 803 size_t retlen, offset; 804 805 pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", 806 part, log_addr, virt_addr); 807 bsize = 1 << part->header.EraseUnitSize; 808 eun = log_addr / bsize; 809 blk = (log_addr % bsize) / SECTOR_SIZE; 810 offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) + 811 le32_to_cpu(part->header.BAMOffset)); 812 813#ifdef PSYCHO_DEBUG 814 ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, 815 (u_char *)&old_addr); 816 if (ret) { 817 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); 818 return ret; 819 } 820 old_addr = le32_to_cpu(old_addr); 821 822 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) || 823 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) || 824 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) { 825 static int ne = 0; 826 if (++ne < 5) { 827 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n"); 828 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x" 829 ", new = 0x%x\n", log_addr, old_addr, virt_addr); 830 } 831 return -EIO; 832 } 833#endif 834 le_virt_addr = cpu_to_le32(virt_addr); 835 if (part->bam_index == eun) { 836#ifdef PSYCHO_DEBUG 837 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) { 838 static int ne = 0; 839 if (++ne < 5) { 840 printk(KERN_NOTICE "ftl_cs: set_bam_entry() " 841 "inconsistency!\n"); 842 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache" 843 " = 0x%x\n", 844 le32_to_cpu(part->bam_cache[blk]), old_addr); 845 } 846 return -EIO; 847 } 848#endif 849 part->bam_cache[blk] = le_virt_addr; 850 } 851 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, 852 (u_char *)&le_virt_addr); 853 854 if (ret) { 855 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n"); 856 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n", 857 log_addr, virt_addr); 858 } 859 return ret; 860} /* set_bam_entry */ 861 862static int ftl_write(partition_t *part, caddr_t buffer, 863 u_long sector, u_long nblocks) 864{ 865 uint32_t bsize, log_addr, virt_addr, old_addr, blk; 866 u_long i; 867 int ret; 868 size_t retlen, offset; 869 870 pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n", 871 part, sector, nblocks); 872 if (!(part->state & FTL_FORMATTED)) { 873 printk(KERN_NOTICE "ftl_cs: bad partition\n"); 874 return -EIO; 875 } 876 /* See if we need to reclaim space, before we start */ 877 while (part->FreeTotal < nblocks) { 878 ret = reclaim_block(part); 879 if (ret) 880 return ret; 881 } 882 883 bsize = 1 << part->header.EraseUnitSize; 884 885 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA; 886 for (i = 0; i < nblocks; i++) { 887 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) { 888 printk(KERN_NOTICE "ftl_cs: bad write offset\n"); 889 return -EIO; 890 } 891 892 /* Grab a free block */ 893 blk = find_free(part); 894 if (blk == 0) { 895 static int ne = 0; 896 if (++ne < 5) 897 printk(KERN_NOTICE "ftl_cs: internal error: " 898 "no free blocks!\n"); 899 return -ENOSPC; 900 } 901 902 /* Tag the BAM entry, and write the new block */ 903 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE; 904 part->EUNInfo[part->bam_index].Free--; 905 part->FreeTotal--; 906 if (set_bam_entry(part, log_addr, 0xfffffffe)) 907 return -EIO; 908 part->EUNInfo[part->bam_index].Deleted++; 909 offset = (part->EUNInfo[part->bam_index].Offset + 910 blk * SECTOR_SIZE); 911 ret = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer); 912 913 if (ret) { 914 printk(KERN_NOTICE "ftl_cs: block write failed!\n"); 915 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr" 916 " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr, 917 offset); 918 return -EIO; 919 } 920 921 /* Only delete the old entry when the new entry is ready */ 922 old_addr = part->VirtualBlockMap[sector+i]; 923 if (old_addr != 0xffffffff) { 924 part->VirtualBlockMap[sector+i] = 0xffffffff; 925 part->EUNInfo[old_addr/bsize].Deleted++; 926 if (set_bam_entry(part, old_addr, 0)) 927 return -EIO; 928 } 929 930 /* Finally, set up the new pointers */ 931 if (set_bam_entry(part, log_addr, virt_addr)) 932 return -EIO; 933 part->VirtualBlockMap[sector+i] = log_addr; 934 part->EUNInfo[part->bam_index].Deleted--; 935 936 buffer += SECTOR_SIZE; 937 virt_addr += SECTOR_SIZE; 938 } 939 return 0; 940} /* ftl_write */ 941 942static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) 943{ 944 partition_t *part = container_of(dev, struct partition_t, mbd); 945 u_long sect; 946 947 /* Sort of arbitrary: round size down to 4KiB boundary */ 948 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; 949 950 geo->heads = 1; 951 geo->sectors = 8; 952 geo->cylinders = sect >> 3; 953 954 return 0; 955} 956 957static int ftl_readsect(struct mtd_blktrans_dev *dev, 958 unsigned long block, char *buf) 959{ 960 return ftl_read((void *)dev, buf, block, 1); 961} 962 963static int ftl_writesect(struct mtd_blktrans_dev *dev, 964 unsigned long block, char *buf) 965{ 966 return ftl_write((void *)dev, buf, block, 1); 967} 968 969static int ftl_discardsect(struct mtd_blktrans_dev *dev, 970 unsigned long sector, unsigned nr_sects) 971{ 972 partition_t *part = container_of(dev, struct partition_t, mbd); 973 uint32_t bsize = 1 << part->header.EraseUnitSize; 974 975 pr_debug("FTL erase sector %ld for %d sectors\n", 976 sector, nr_sects); 977 978 while (nr_sects) { 979 uint32_t old_addr = part->VirtualBlockMap[sector]; 980 if (old_addr != 0xffffffff) { 981 part->VirtualBlockMap[sector] = 0xffffffff; 982 part->EUNInfo[old_addr/bsize].Deleted++; 983 if (set_bam_entry(part, old_addr, 0)) 984 return -EIO; 985 } 986 nr_sects--; 987 sector++; 988 } 989 990 return 0; 991} 992/*====================================================================*/ 993 994static void ftl_freepart(partition_t *part) 995{ 996 vfree(part->VirtualBlockMap); 997 part->VirtualBlockMap = NULL; 998 kfree(part->EUNInfo); 999 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 1006static 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 1039static void ftl_remove_dev(struct mtd_blktrans_dev *dev) 1040{ 1041 del_mtd_blktrans_dev(dev); 1042 ftl_freepart((partition_t *)dev); 1043} 1044 1045static 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 1059module_mtd_blktrans(ftl_tr); 1060 1061MODULE_LICENSE("Dual MPL/GPL"); 1062MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); 1063MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices"); 1064