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_objs(struct eun_info_t, part->DataUnits, GFP_KERNEL); 205 if (!part->EUNInfo) 206 goto out; 207 for (i = 0; i < part->DataUnits; i++) 208 part->EUNInfo[i].Offset = 0xffffffff; 209 part->XferInfo = 210 kmalloc_objs(struct xfer_info_t, part->header.NumTransferUnits, 211 GFP_KERNEL); 212 if (!part->XferInfo) 213 goto out_EUNInfo; 214 215 xvalid = xtrans = 0; 216 for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { 217 offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) 218 << part->header.EraseUnitSize); 219 ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval, 220 (unsigned char *)&header); 221 222 if (ret) 223 goto out_XferInfo; 224 225 ret = -1; 226 /* Is this a transfer partition? */ 227 hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0); 228 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) && 229 (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) { 230 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset; 231 part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount = 232 le32_to_cpu(header.EraseCount); 233 xvalid++; 234 } else { 235 if (xtrans == part->header.NumTransferUnits) { 236 printk(KERN_NOTICE "ftl_cs: format error: too many " 237 "transfer units!\n"); 238 goto out_XferInfo; 239 } 240 if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) { 241 part->XferInfo[xtrans].state = XFER_PREPARED; 242 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount); 243 } else { 244 part->XferInfo[xtrans].state = XFER_UNKNOWN; 245 /* Pick anything reasonable for the erase count */ 246 part->XferInfo[xtrans].EraseCount = 247 le32_to_cpu(part->header.EraseCount); 248 } 249 part->XferInfo[xtrans].Offset = offset; 250 xtrans++; 251 } 252 } 253 /* Check for format trouble */ 254 header = part->header; 255 if ((xtrans != header.NumTransferUnits) || 256 (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) { 257 printk(KERN_NOTICE "ftl_cs: format error: erase units " 258 "don't add up!\n"); 259 goto out_XferInfo; 260 } 261 262 /* Set up virtual page map */ 263 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; 264 part->VirtualBlockMap = vmalloc_array(blocks, sizeof(uint32_t)); 265 if (!part->VirtualBlockMap) 266 goto out_XferInfo; 267 268 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t)); 269 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize; 270 271 part->bam_cache = kmalloc_array(part->BlocksPerUnit, sizeof(uint32_t), 272 GFP_KERNEL); 273 if (!part->bam_cache) 274 goto out_VirtualBlockMap; 275 276 part->bam_index = 0xffff; 277 part->FreeTotal = 0; 278 279 for (i = 0; i < part->DataUnits; i++) { 280 part->EUNInfo[i].Free = 0; 281 part->EUNInfo[i].Deleted = 0; 282 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); 283 284 ret = mtd_read(part->mbd.mtd, offset, 285 part->BlocksPerUnit * sizeof(uint32_t), &retval, 286 (unsigned char *)part->bam_cache); 287 288 if (ret) 289 goto out_bam_cache; 290 291 for (j = 0; j < part->BlocksPerUnit; j++) { 292 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) { 293 part->EUNInfo[i].Free++; 294 part->FreeTotal++; 295 } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) && 296 (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks)) 297 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] = 298 (i << header.EraseUnitSize) + (j << header.BlockSize); 299 else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j]))) 300 part->EUNInfo[i].Deleted++; 301 } 302 } 303 304 ret = 0; 305 goto out; 306 307 out_bam_cache: 308 kfree(part->bam_cache); 309 out_VirtualBlockMap: 310 vfree(part->VirtualBlockMap); 311 out_XferInfo: 312 kfree(part->XferInfo); 313 out_EUNInfo: 314 kfree(part->EUNInfo); 315 out: 316 return ret; 317 } /* build_maps */ 318 319 /*====================================================================== 320 321 Erase_xfer() schedules an asynchronous erase operation for a 322 transfer unit. 323 324 ======================================================================*/ 325 326 static int erase_xfer(partition_t *part, 327 uint16_t xfernum) 328 { 329 int ret; 330 struct xfer_info_t *xfer; 331 struct erase_info *erase; 332 333 xfer = &part->XferInfo[xfernum]; 334 pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); 335 xfer->state = XFER_ERASING; 336 337 /* Is there a free erase slot? Always in MTD. */ 338 339 340 erase=kmalloc_obj(struct erase_info, GFP_KERNEL); 341 if (!erase) 342 return -ENOMEM; 343 344 erase->addr = xfer->Offset; 345 erase->len = 1ULL << part->header.EraseUnitSize; 346 347 ret = mtd_erase(part->mbd.mtd, erase); 348 if (!ret) { 349 xfer->state = XFER_ERASED; 350 xfer->EraseCount++; 351 } else { 352 xfer->state = XFER_FAILED; 353 pr_notice("ftl_cs: erase failed: err = %d\n", ret); 354 } 355 356 kfree(erase); 357 358 return ret; 359 } /* erase_xfer */ 360 361 /*====================================================================== 362 363 Prepare_xfer() takes a freshly erased transfer unit and gives 364 it an appropriate header. 365 366 ======================================================================*/ 367 368 static int prepare_xfer(partition_t *part, int i) 369 { 370 erase_unit_header_t header; 371 struct xfer_info_t *xfer; 372 int nbam, ret; 373 uint32_t ctl; 374 ssize_t retlen; 375 loff_t offset; 376 377 xfer = &part->XferInfo[i]; 378 xfer->state = XFER_FAILED; 379 380 pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); 381 382 /* Write the transfer unit header */ 383 header = part->header; 384 header.LogicalEUN = cpu_to_le16(0xffff); 385 header.EraseCount = cpu_to_le32(xfer->EraseCount); 386 387 ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen, 388 (u_char *)&header); 389 390 if (ret) { 391 return ret; 392 } 393 394 /* Write the BAM stub */ 395 nbam = DIV_ROUND_UP(part->BlocksPerUnit * sizeof(uint32_t) + 396 le32_to_cpu(part->header.BAMOffset), SECTOR_SIZE); 397 398 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset); 399 ctl = cpu_to_le32(BLOCK_CONTROL); 400 401 for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) { 402 403 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, 404 (u_char *)&ctl); 405 406 if (ret) 407 return ret; 408 } 409 xfer->state = XFER_PREPARED; 410 return 0; 411 412 } /* prepare_xfer */ 413 414 /*====================================================================== 415 416 Copy_erase_unit() takes a full erase block and a transfer unit, 417 copies everything to the transfer unit, then swaps the block 418 pointers. 419 420 All data blocks are copied to the corresponding blocks in the 421 target unit, so the virtual block map does not need to be 422 updated. 423 424 ======================================================================*/ 425 426 static int copy_erase_unit(partition_t *part, uint16_t srcunit, 427 uint16_t xferunit) 428 { 429 u_char buf[SECTOR_SIZE]; 430 struct eun_info_t *eun; 431 struct xfer_info_t *xfer; 432 uint32_t src, dest, free, i; 433 uint16_t unit; 434 int ret; 435 ssize_t retlen; 436 loff_t offset; 437 uint16_t srcunitswap = cpu_to_le16(srcunit); 438 439 eun = &part->EUNInfo[srcunit]; 440 xfer = &part->XferInfo[xferunit]; 441 pr_debug("ftl_cs: copying block 0x%x to 0x%x\n", 442 eun->Offset, xfer->Offset); 443 444 445 /* Read current BAM */ 446 if (part->bam_index != srcunit) { 447 448 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); 449 450 ret = mtd_read(part->mbd.mtd, offset, 451 part->BlocksPerUnit * sizeof(uint32_t), &retlen, 452 (u_char *)(part->bam_cache)); 453 454 /* mark the cache bad, in case we get an error later */ 455 part->bam_index = 0xffff; 456 457 if (ret) { 458 printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); 459 return ret; 460 } 461 } 462 463 /* Write the LogicalEUN for the transfer unit */ 464 xfer->state = XFER_UNKNOWN; 465 offset = xfer->Offset + 20; /* Bad! */ 466 unit = cpu_to_le16(0x7fff); 467 468 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen, 469 (u_char *)&unit); 470 471 if (ret) { 472 printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n"); 473 return ret; 474 } 475 476 /* Copy all data blocks from source unit to transfer unit */ 477 src = eun->Offset; dest = xfer->Offset; 478 479 free = 0; 480 ret = 0; 481 for (i = 0; i < part->BlocksPerUnit; i++) { 482 switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) { 483 case BLOCK_CONTROL: 484 /* This gets updated later */ 485 break; 486 case BLOCK_DATA: 487 case BLOCK_REPLACEMENT: 488 ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen, 489 (u_char *)buf); 490 if (ret) { 491 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n"); 492 return ret; 493 } 494 495 496 ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen, 497 (u_char *)buf); 498 if (ret) { 499 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n"); 500 return ret; 501 } 502 503 break; 504 default: 505 /* All other blocks must be free */ 506 part->bam_cache[i] = cpu_to_le32(0xffffffff); 507 free++; 508 break; 509 } 510 src += SECTOR_SIZE; 511 dest += SECTOR_SIZE; 512 } 513 514 /* Write the BAM to the transfer unit */ 515 ret = mtd_write(part->mbd.mtd, 516 xfer->Offset + le32_to_cpu(part->header.BAMOffset), 517 part->BlocksPerUnit * sizeof(int32_t), 518 &retlen, 519 (u_char *)part->bam_cache); 520 if (ret) { 521 printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n"); 522 return ret; 523 } 524 525 526 /* All clear? Then update the LogicalEUN again */ 527 ret = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t), 528 &retlen, (u_char *)&srcunitswap); 529 530 if (ret) { 531 printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n"); 532 return ret; 533 } 534 535 536 /* Update the maps and usage stats*/ 537 swap(xfer->EraseCount, eun->EraseCount); 538 swap(xfer->Offset, eun->Offset); 539 part->FreeTotal -= eun->Free; 540 part->FreeTotal += free; 541 eun->Free = free; 542 eun->Deleted = 0; 543 544 /* Now, the cache should be valid for the new block */ 545 part->bam_index = srcunit; 546 547 return 0; 548 } /* copy_erase_unit */ 549 550 /*====================================================================== 551 552 reclaim_block() picks a full erase unit and a transfer unit and 553 then calls copy_erase_unit() to copy one to the other. Then, it 554 schedules an erase on the expired block. 555 556 What's a good way to decide which transfer unit and which erase 557 unit to use? Beats me. My way is to always pick the transfer 558 unit with the fewest erases, and usually pick the data unit with 559 the most deleted blocks. But with a small probability, pick the 560 oldest data unit instead. This means that we generally postpone 561 the next reclamation as long as possible, but shuffle static 562 stuff around a bit for wear leveling. 563 564 ======================================================================*/ 565 566 static int reclaim_block(partition_t *part) 567 { 568 uint16_t i, eun, xfer; 569 uint32_t best; 570 int queued, ret; 571 572 pr_debug("ftl_cs: reclaiming space...\n"); 573 pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits); 574 /* Pick the least erased transfer unit */ 575 best = 0xffffffff; xfer = 0xffff; 576 do { 577 queued = 0; 578 for (i = 0; i < part->header.NumTransferUnits; i++) { 579 int n=0; 580 if (part->XferInfo[i].state == XFER_UNKNOWN) { 581 pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i); 582 n=1; 583 erase_xfer(part, i); 584 } 585 if (part->XferInfo[i].state == XFER_ERASING) { 586 pr_debug("XferInfo[%d].state == XFER_ERASING\n",i); 587 n=1; 588 queued = 1; 589 } 590 else if (part->XferInfo[i].state == XFER_ERASED) { 591 pr_debug("XferInfo[%d].state == XFER_ERASED\n",i); 592 n=1; 593 prepare_xfer(part, i); 594 } 595 if (part->XferInfo[i].state == XFER_PREPARED) { 596 pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i); 597 n=1; 598 if (part->XferInfo[i].EraseCount <= best) { 599 best = part->XferInfo[i].EraseCount; 600 xfer = i; 601 } 602 } 603 if (!n) 604 pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); 605 606 } 607 if (xfer == 0xffff) { 608 if (queued) { 609 pr_debug("ftl_cs: waiting for transfer " 610 "unit to be prepared...\n"); 611 mtd_sync(part->mbd.mtd); 612 } else { 613 static int ne = 0; 614 if (++ne < 5) 615 printk(KERN_NOTICE "ftl_cs: reclaim failed: no " 616 "suitable transfer units!\n"); 617 else 618 pr_debug("ftl_cs: reclaim failed: no " 619 "suitable transfer units!\n"); 620 621 return -EIO; 622 } 623 } 624 } while (xfer == 0xffff); 625 626 eun = 0; 627 if ((jiffies % shuffle_freq) == 0) { 628 pr_debug("ftl_cs: recycling freshest block...\n"); 629 best = 0xffffffff; 630 for (i = 0; i < part->DataUnits; i++) 631 if (part->EUNInfo[i].EraseCount <= best) { 632 best = part->EUNInfo[i].EraseCount; 633 eun = i; 634 } 635 } else { 636 best = 0; 637 for (i = 0; i < part->DataUnits; i++) 638 if (part->EUNInfo[i].Deleted >= best) { 639 best = part->EUNInfo[i].Deleted; 640 eun = i; 641 } 642 if (best == 0) { 643 static int ne = 0; 644 if (++ne < 5) 645 printk(KERN_NOTICE "ftl_cs: reclaim failed: " 646 "no free blocks!\n"); 647 else 648 pr_debug("ftl_cs: reclaim failed: " 649 "no free blocks!\n"); 650 651 return -EIO; 652 } 653 } 654 ret = copy_erase_unit(part, eun, xfer); 655 if (!ret) 656 erase_xfer(part, xfer); 657 else 658 printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n"); 659 return ret; 660 } /* reclaim_block */ 661 662 /*====================================================================== 663 664 Find_free() searches for a free block. If necessary, it updates 665 the BAM cache for the erase unit containing the free block. It 666 returns the block index -- the erase unit is just the currently 667 cached unit. If there are no free blocks, it returns 0 -- this 668 is never a valid data block because it contains the header. 669 670 ======================================================================*/ 671 672 #ifdef PSYCHO_DEBUG 673 static void dump_lists(partition_t *part) 674 { 675 int i; 676 printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal); 677 for (i = 0; i < part->DataUnits; i++) 678 printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, " 679 "%d deleted\n", i, 680 part->EUNInfo[i].Offset >> part->header.EraseUnitSize, 681 part->EUNInfo[i].Free, part->EUNInfo[i].Deleted); 682 } 683 #endif 684 685 static uint32_t find_free(partition_t *part) 686 { 687 uint16_t stop, eun; 688 uint32_t blk; 689 size_t retlen; 690 int ret; 691 692 /* Find an erase unit with some free space */ 693 stop = (part->bam_index == 0xffff) ? 0 : part->bam_index; 694 eun = stop; 695 do { 696 if (part->EUNInfo[eun].Free != 0) break; 697 /* Wrap around at end of table */ 698 if (++eun == part->DataUnits) eun = 0; 699 } while (eun != stop); 700 701 if (part->EUNInfo[eun].Free == 0) 702 return 0; 703 704 /* Is this unit's BAM cached? */ 705 if (eun != part->bam_index) { 706 /* Invalidate cache */ 707 part->bam_index = 0xffff; 708 709 ret = mtd_read(part->mbd.mtd, 710 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), 711 part->BlocksPerUnit * sizeof(uint32_t), 712 &retlen, 713 (u_char *)(part->bam_cache)); 714 715 if (ret) { 716 printk(KERN_WARNING"ftl: Error reading BAM in find_free\n"); 717 return 0; 718 } 719 part->bam_index = eun; 720 } 721 722 /* Find a free block */ 723 for (blk = 0; blk < part->BlocksPerUnit; blk++) 724 if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break; 725 if (blk == part->BlocksPerUnit) { 726 #ifdef PSYCHO_DEBUG 727 static int ne = 0; 728 if (++ne == 1) 729 dump_lists(part); 730 #endif 731 printk(KERN_NOTICE "ftl_cs: bad free list!\n"); 732 return 0; 733 } 734 pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun); 735 return blk; 736 737 } /* find_free */ 738 739 740 /*====================================================================== 741 742 Read a series of sectors from an FTL partition. 743 744 ======================================================================*/ 745 746 static int ftl_read(partition_t *part, caddr_t buffer, 747 u_long sector, u_long nblocks) 748 { 749 uint32_t log_addr, bsize; 750 u_long i; 751 int ret; 752 size_t offset, retlen; 753 754 pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", 755 part, sector, nblocks); 756 if (!(part->state & FTL_FORMATTED)) { 757 printk(KERN_NOTICE "ftl_cs: bad partition\n"); 758 return -EIO; 759 } 760 bsize = 1 << part->header.EraseUnitSize; 761 762 for (i = 0; i < nblocks; i++) { 763 if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) { 764 printk(KERN_NOTICE "ftl_cs: bad read offset\n"); 765 return -EIO; 766 } 767 log_addr = part->VirtualBlockMap[sector+i]; 768 if (log_addr == 0xffffffff) 769 memset(buffer, 0, SECTOR_SIZE); 770 else { 771 offset = (part->EUNInfo[log_addr / bsize].Offset 772 + (log_addr % bsize)); 773 ret = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, 774 (u_char *)buffer); 775 776 if (ret) { 777 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n"); 778 return ret; 779 } 780 } 781 buffer += SECTOR_SIZE; 782 } 783 return 0; 784 } /* ftl_read */ 785 786 /*====================================================================== 787 788 Write a series of sectors to an FTL partition 789 790 ======================================================================*/ 791 792 static int set_bam_entry(partition_t *part, uint32_t log_addr, 793 uint32_t virt_addr) 794 { 795 uint32_t bsize, blk, le_virt_addr; 796 #ifdef PSYCHO_DEBUG 797 uint32_t old_addr; 798 #endif 799 uint16_t eun; 800 int ret; 801 size_t retlen, offset; 802 803 pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", 804 part, log_addr, virt_addr); 805 bsize = 1 << part->header.EraseUnitSize; 806 eun = log_addr / bsize; 807 blk = (log_addr % bsize) / SECTOR_SIZE; 808 offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) + 809 le32_to_cpu(part->header.BAMOffset)); 810 811 #ifdef PSYCHO_DEBUG 812 ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, 813 (u_char *)&old_addr); 814 if (ret) { 815 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); 816 return ret; 817 } 818 old_addr = le32_to_cpu(old_addr); 819 820 if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) || 821 ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) || 822 (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) { 823 static int ne = 0; 824 if (++ne < 5) { 825 printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n"); 826 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x" 827 ", new = 0x%x\n", log_addr, old_addr, virt_addr); 828 } 829 return -EIO; 830 } 831 #endif 832 le_virt_addr = cpu_to_le32(virt_addr); 833 if (part->bam_index == eun) { 834 #ifdef PSYCHO_DEBUG 835 if (le32_to_cpu(part->bam_cache[blk]) != old_addr) { 836 static int ne = 0; 837 if (++ne < 5) { 838 printk(KERN_NOTICE "ftl_cs: set_bam_entry() " 839 "inconsistency!\n"); 840 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache" 841 " = 0x%x\n", 842 le32_to_cpu(part->bam_cache[blk]), old_addr); 843 } 844 return -EIO; 845 } 846 #endif 847 part->bam_cache[blk] = le_virt_addr; 848 } 849 ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, 850 (u_char *)&le_virt_addr); 851 852 if (ret) { 853 printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n"); 854 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n", 855 log_addr, virt_addr); 856 } 857 return ret; 858 } /* set_bam_entry */ 859 860 static int ftl_write(partition_t *part, caddr_t buffer, 861 u_long sector, u_long nblocks) 862 { 863 uint32_t bsize, log_addr, virt_addr, old_addr, blk; 864 u_long i; 865 int ret; 866 size_t retlen, offset; 867 868 pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n", 869 part, sector, nblocks); 870 if (!(part->state & FTL_FORMATTED)) { 871 printk(KERN_NOTICE "ftl_cs: bad partition\n"); 872 return -EIO; 873 } 874 /* See if we need to reclaim space, before we start */ 875 while (part->FreeTotal < nblocks) { 876 ret = reclaim_block(part); 877 if (ret) 878 return ret; 879 } 880 881 bsize = 1 << part->header.EraseUnitSize; 882 883 virt_addr = sector * SECTOR_SIZE | BLOCK_DATA; 884 for (i = 0; i < nblocks; i++) { 885 if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) { 886 printk(KERN_NOTICE "ftl_cs: bad write offset\n"); 887 return -EIO; 888 } 889 890 /* Grab a free block */ 891 blk = find_free(part); 892 if (blk == 0) { 893 static int ne = 0; 894 if (++ne < 5) 895 printk(KERN_NOTICE "ftl_cs: internal error: " 896 "no free blocks!\n"); 897 return -ENOSPC; 898 } 899 900 /* Tag the BAM entry, and write the new block */ 901 log_addr = part->bam_index * bsize + blk * SECTOR_SIZE; 902 part->EUNInfo[part->bam_index].Free--; 903 part->FreeTotal--; 904 if (set_bam_entry(part, log_addr, 0xfffffffe)) 905 return -EIO; 906 part->EUNInfo[part->bam_index].Deleted++; 907 offset = (part->EUNInfo[part->bam_index].Offset + 908 blk * SECTOR_SIZE); 909 ret = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer); 910 911 if (ret) { 912 printk(KERN_NOTICE "ftl_cs: block write failed!\n"); 913 printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr" 914 " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr, 915 offset); 916 return -EIO; 917 } 918 919 /* Only delete the old entry when the new entry is ready */ 920 old_addr = part->VirtualBlockMap[sector+i]; 921 if (old_addr != 0xffffffff) { 922 part->VirtualBlockMap[sector+i] = 0xffffffff; 923 part->EUNInfo[old_addr/bsize].Deleted++; 924 if (set_bam_entry(part, old_addr, 0)) 925 return -EIO; 926 } 927 928 /* Finally, set up the new pointers */ 929 if (set_bam_entry(part, log_addr, virt_addr)) 930 return -EIO; 931 part->VirtualBlockMap[sector+i] = log_addr; 932 part->EUNInfo[part->bam_index].Deleted--; 933 934 buffer += SECTOR_SIZE; 935 virt_addr += SECTOR_SIZE; 936 } 937 return 0; 938 } /* ftl_write */ 939 940 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) 941 { 942 partition_t *part = container_of(dev, struct partition_t, mbd); 943 u_long sect; 944 945 /* Sort of arbitrary: round size down to 4KiB boundary */ 946 sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; 947 948 geo->heads = 1; 949 geo->sectors = 8; 950 geo->cylinders = sect >> 3; 951 952 return 0; 953 } 954 955 static int ftl_readsect(struct mtd_blktrans_dev *dev, 956 unsigned long block, char *buf) 957 { 958 return ftl_read((void *)dev, buf, block, 1); 959 } 960 961 static int ftl_writesect(struct mtd_blktrans_dev *dev, 962 unsigned long block, char *buf) 963 { 964 return ftl_write((void *)dev, buf, block, 1); 965 } 966 967 static int ftl_discardsect(struct mtd_blktrans_dev *dev, 968 unsigned long sector, unsigned nr_sects) 969 { 970 partition_t *part = container_of(dev, struct partition_t, mbd); 971 uint32_t bsize = 1 << part->header.EraseUnitSize; 972 973 pr_debug("FTL erase sector %ld for %d sectors\n", 974 sector, nr_sects); 975 976 while (nr_sects) { 977 uint32_t old_addr = part->VirtualBlockMap[sector]; 978 if (old_addr != 0xffffffff) { 979 part->VirtualBlockMap[sector] = 0xffffffff; 980 part->EUNInfo[old_addr/bsize].Deleted++; 981 if (set_bam_entry(part, old_addr, 0)) 982 return -EIO; 983 } 984 nr_sects--; 985 sector++; 986 } 987 988 return 0; 989 } 990 /*====================================================================*/ 991 992 static void ftl_freepart(partition_t *part) 993 { 994 vfree(part->VirtualBlockMap); 995 part->VirtualBlockMap = NULL; 996 kfree(part->EUNInfo); 997 part->EUNInfo = NULL; 998 kfree(part->XferInfo); 999 part->XferInfo = NULL; 1000 kfree(part->bam_cache); 1001 part->bam_cache = NULL; 1002 } /* ftl_freepart */ 1003 1004 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) 1005 { 1006 partition_t *partition; 1007 1008 partition = kzalloc_obj(partition_t, GFP_KERNEL); 1009 1010 if (!partition) { 1011 printk(KERN_WARNING "No memory to scan for FTL on %s\n", 1012 mtd->name); 1013 return; 1014 } 1015 1016 partition->mbd.mtd = mtd; 1017 1018 if ((scan_header(partition) == 0) && 1019 (build_maps(partition) == 0)) { 1020 1021 partition->state = FTL_FORMATTED; 1022 #ifdef PCMCIA_DEBUG 1023 printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", 1024 le32_to_cpu(partition->header.FormattedSize) >> 10); 1025 #endif 1026 partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9; 1027 1028 partition->mbd.tr = tr; 1029 partition->mbd.devnum = -1; 1030 if (!add_mtd_blktrans_dev(&partition->mbd)) 1031 return; 1032 } 1033 1034 kfree(partition); 1035 } 1036 1037 static void ftl_remove_dev(struct mtd_blktrans_dev *dev) 1038 { 1039 del_mtd_blktrans_dev(dev); 1040 ftl_freepart((partition_t *)dev); 1041 } 1042 1043 static struct mtd_blktrans_ops ftl_tr = { 1044 .name = "ftl", 1045 .major = FTL_MAJOR, 1046 .part_bits = PART_BITS, 1047 .blksize = SECTOR_SIZE, 1048 .readsect = ftl_readsect, 1049 .writesect = ftl_writesect, 1050 .discard = ftl_discardsect, 1051 .getgeo = ftl_getgeo, 1052 .add_mtd = ftl_add_mtd, 1053 .remove_dev = ftl_remove_dev, 1054 .owner = THIS_MODULE, 1055 }; 1056 1057 module_mtd_blktrans(ftl_tr); 1058 1059 MODULE_LICENSE("Dual MPL/GPL"); 1060 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); 1061 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices"); 1062