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