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