1 /* 2 * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) 3 * 4 * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) 5 * 6 * Based heavily on the nftlcore.c code which is: 7 * (c) 1999 Machine Vision Holdings, Inc. 8 * Author: David Woodhouse <dwmw2@infradead.org> 9 * 10 * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $ 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 27 #include <linux/kernel.h> 28 #include <linux/module.h> 29 #include <linux/delay.h> 30 #include <linux/slab.h> 31 #include <linux/sched.h> 32 #include <linux/init.h> 33 #include <linux/kmod.h> 34 #include <linux/hdreg.h> 35 #include <linux/mtd/mtd.h> 36 #include <linux/mtd/nftl.h> 37 #include <linux/mtd/inftl.h> 38 #include <linux/mtd/nand.h> 39 #include <asm/uaccess.h> 40 #include <asm/errno.h> 41 #include <asm/io.h> 42 43 /* 44 * Maximum number of loops while examining next block, to have a 45 * chance to detect consistency problems (they should never happen 46 * because of the checks done in the mounting. 47 */ 48 #define MAX_LOOPS 10000 49 50 static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) 51 { 52 struct INFTLrecord *inftl; 53 unsigned long temp; 54 55 if (mtd->type != MTD_NANDFLASH) 56 return; 57 /* OK, this is moderately ugly. But probably safe. Alternatives? */ 58 if (memcmp(mtd->name, "DiskOnChip", 10)) 59 return; 60 61 if (!mtd->block_isbad) { 62 printk(KERN_ERR 63 "INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n" 64 "Please use the new diskonchip driver under the NAND subsystem.\n"); 65 return; 66 } 67 68 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); 69 70 inftl = kzalloc(sizeof(*inftl), GFP_KERNEL); 71 72 if (!inftl) { 73 printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); 74 return; 75 } 76 77 inftl->mbd.mtd = mtd; 78 inftl->mbd.devnum = -1; 79 80 inftl->mbd.tr = tr; 81 82 if (INFTL_mount(inftl) < 0) { 83 printk(KERN_WARNING "INFTL: could not mount device\n"); 84 kfree(inftl); 85 return; 86 } 87 88 /* OK, it's a new one. Set up all the data structures. */ 89 90 /* Calculate geometry */ 91 inftl->cylinders = 1024; 92 inftl->heads = 16; 93 94 temp = inftl->cylinders * inftl->heads; 95 inftl->sectors = inftl->mbd.size / temp; 96 if (inftl->mbd.size % temp) { 97 inftl->sectors++; 98 temp = inftl->cylinders * inftl->sectors; 99 inftl->heads = inftl->mbd.size / temp; 100 101 if (inftl->mbd.size % temp) { 102 inftl->heads++; 103 temp = inftl->heads * inftl->sectors; 104 inftl->cylinders = inftl->mbd.size / temp; 105 } 106 } 107 108 if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { 109 /* 110 Oh no we don't have 111 mbd.size == heads * cylinders * sectors 112 */ 113 printk(KERN_WARNING "INFTL: cannot calculate a geometry to " 114 "match size of 0x%lx.\n", inftl->mbd.size); 115 printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " 116 "(== 0x%lx sects)\n", 117 inftl->cylinders, inftl->heads , inftl->sectors, 118 (long)inftl->cylinders * (long)inftl->heads * 119 (long)inftl->sectors ); 120 } 121 122 if (add_mtd_blktrans_dev(&inftl->mbd)) { 123 kfree(inftl->PUtable); 124 kfree(inftl->VUtable); 125 kfree(inftl); 126 return; 127 } 128 #ifdef PSYCHO_DEBUG 129 printk(KERN_INFO "INFTL: Found new inftl%c\n", inftl->mbd.devnum + 'a'); 130 #endif 131 return; 132 } 133 134 static void inftl_remove_dev(struct mtd_blktrans_dev *dev) 135 { 136 struct INFTLrecord *inftl = (void *)dev; 137 138 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum); 139 140 del_mtd_blktrans_dev(dev); 141 142 kfree(inftl->PUtable); 143 kfree(inftl->VUtable); 144 kfree(inftl); 145 } 146 147 /* 148 * Actual INFTL access routines. 149 */ 150 151 /* 152 * Read oob data from flash 153 */ 154 int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, 155 size_t *retlen, uint8_t *buf) 156 { 157 struct mtd_oob_ops ops; 158 int res; 159 160 ops.mode = MTD_OOB_PLACE; 161 ops.ooboffs = offs & (mtd->writesize - 1); 162 ops.ooblen = len; 163 ops.oobbuf = buf; 164 ops.datbuf = NULL; 165 166 res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops); 167 *retlen = ops.oobretlen; 168 return res; 169 } 170 171 /* 172 * Write oob data to flash 173 */ 174 int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, 175 size_t *retlen, uint8_t *buf) 176 { 177 struct mtd_oob_ops ops; 178 int res; 179 180 ops.mode = MTD_OOB_PLACE; 181 ops.ooboffs = offs & (mtd->writesize - 1); 182 ops.ooblen = len; 183 ops.oobbuf = buf; 184 ops.datbuf = NULL; 185 186 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops); 187 *retlen = ops.oobretlen; 188 return res; 189 } 190 191 /* 192 * Write data and oob to flash 193 */ 194 static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len, 195 size_t *retlen, uint8_t *buf, uint8_t *oob) 196 { 197 struct mtd_oob_ops ops; 198 int res; 199 200 ops.mode = MTD_OOB_PLACE; 201 ops.ooboffs = offs; 202 ops.ooblen = mtd->oobsize; 203 ops.oobbuf = oob; 204 ops.datbuf = buf; 205 ops.len = len; 206 207 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops); 208 *retlen = ops.retlen; 209 return res; 210 } 211 212 /* 213 * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition. 214 * This function is used when the give Virtual Unit Chain. 215 */ 216 static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) 217 { 218 u16 pot = inftl->LastFreeEUN; 219 int silly = inftl->nb_blocks; 220 221 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p," 222 "desperate=%d)\n", inftl, desperate); 223 224 /* 225 * Normally, we force a fold to happen before we run out of free 226 * blocks completely. 227 */ 228 if (!desperate && inftl->numfreeEUNs < 2) { 229 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " 230 "EUNs (%d)\n", inftl->numfreeEUNs); 231 return 0xffff; 232 } 233 234 /* Scan for a free block */ 235 do { 236 if (inftl->PUtable[pot] == BLOCK_FREE) { 237 inftl->LastFreeEUN = pot; 238 return pot; 239 } 240 241 if (++pot > inftl->lastEUN) 242 pot = 0; 243 244 if (!silly--) { 245 printk(KERN_WARNING "INFTL: no free blocks found! " 246 "EUN range = %d - %d\n", 0, inftl->LastFreeEUN); 247 return BLOCK_NIL; 248 } 249 } while (pot != inftl->LastFreeEUN); 250 251 return BLOCK_NIL; 252 } 253 254 static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock) 255 { 256 u16 BlockMap[MAX_SECTORS_PER_UNIT]; 257 unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT]; 258 unsigned int thisEUN, prevEUN, status; 259 struct mtd_info *mtd = inftl->mbd.mtd; 260 int block, silly; 261 unsigned int targetEUN; 262 struct inftl_oob oob; 263 size_t retlen; 264 265 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d," 266 "pending=%d)\n", inftl, thisVUC, pendingblock); 267 268 memset(BlockMap, 0xff, sizeof(BlockMap)); 269 memset(BlockDeleted, 0, sizeof(BlockDeleted)); 270 271 thisEUN = targetEUN = inftl->VUtable[thisVUC]; 272 273 if (thisEUN == BLOCK_NIL) { 274 printk(KERN_WARNING "INFTL: trying to fold non-existent " 275 "Virtual Unit Chain %d!\n", thisVUC); 276 return BLOCK_NIL; 277 } 278 279 /* 280 * Scan to find the Erase Unit which holds the actual data for each 281 * 512-byte block within the Chain. 282 */ 283 silly = MAX_LOOPS; 284 while (thisEUN < inftl->nb_blocks) { 285 for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) { 286 if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) 287 continue; 288 289 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) 290 + (block * SECTORSIZE), 16, &retlen, 291 (char *)&oob) < 0) 292 status = SECTOR_IGNORE; 293 else 294 status = oob.b.Status | oob.b.Status1; 295 296 switch(status) { 297 case SECTOR_FREE: 298 case SECTOR_IGNORE: 299 break; 300 case SECTOR_USED: 301 BlockMap[block] = thisEUN; 302 continue; 303 case SECTOR_DELETED: 304 BlockDeleted[block] = 1; 305 continue; 306 default: 307 printk(KERN_WARNING "INFTL: unknown status " 308 "for block %d in EUN %d: %x\n", 309 block, thisEUN, status); 310 break; 311 } 312 } 313 314 if (!silly--) { 315 printk(KERN_WARNING "INFTL: infinite loop in Virtual " 316 "Unit Chain 0x%x\n", thisVUC); 317 return BLOCK_NIL; 318 } 319 320 thisEUN = inftl->PUtable[thisEUN]; 321 } 322 323 /* 324 * OK. We now know the location of every block in the Virtual Unit 325 * Chain, and the Erase Unit into which we are supposed to be copying. 326 * Go for it. 327 */ 328 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n", 329 thisVUC, targetEUN); 330 331 for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) { 332 unsigned char movebuf[SECTORSIZE]; 333 int ret; 334 335 /* 336 * If it's in the target EUN already, or if it's pending write, 337 * do nothing. 338 */ 339 if (BlockMap[block] == targetEUN || (pendingblock == 340 (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) { 341 continue; 342 } 343 344 /* 345 * Copy only in non free block (free blocks can only 346 * happen in case of media errors or deleted blocks). 347 */ 348 if (BlockMap[block] == BLOCK_NIL) 349 continue; 350 351 ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + 352 (block * SECTORSIZE), SECTORSIZE, &retlen, 353 movebuf); 354 if (ret < 0 && ret != -EUCLEAN) { 355 ret = mtd->read(mtd, 356 (inftl->EraseSize * BlockMap[block]) + 357 (block * SECTORSIZE), SECTORSIZE, 358 &retlen, movebuf); 359 if (ret != -EIO) 360 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " 361 "away on retry?\n"); 362 } 363 memset(&oob, 0xff, sizeof(struct inftl_oob)); 364 oob.b.Status = oob.b.Status1 = SECTOR_USED; 365 366 inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) + 367 (block * SECTORSIZE), SECTORSIZE, &retlen, 368 movebuf, (char *)&oob); 369 } 370 371 /* 372 * Newest unit in chain now contains data from _all_ older units. 373 * So go through and erase each unit in chain, oldest first. (This 374 * is important, by doing oldest first if we crash/reboot then it 375 * it is relatively simple to clean up the mess). 376 */ 377 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n", 378 thisVUC); 379 380 for (;;) { 381 /* Find oldest unit in chain. */ 382 thisEUN = inftl->VUtable[thisVUC]; 383 prevEUN = BLOCK_NIL; 384 while (inftl->PUtable[thisEUN] != BLOCK_NIL) { 385 prevEUN = thisEUN; 386 thisEUN = inftl->PUtable[thisEUN]; 387 } 388 389 /* Check if we are all done */ 390 if (thisEUN == targetEUN) 391 break; 392 393 if (INFTL_formatblock(inftl, thisEUN) < 0) { 394 /* 395 * Could not erase : mark block as reserved. 396 */ 397 inftl->PUtable[thisEUN] = BLOCK_RESERVED; 398 } else { 399 /* Correctly erased : mark it as free */ 400 inftl->PUtable[thisEUN] = BLOCK_FREE; 401 inftl->PUtable[prevEUN] = BLOCK_NIL; 402 inftl->numfreeEUNs++; 403 } 404 } 405 406 return targetEUN; 407 } 408 409 static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) 410 { 411 /* 412 * This is the part that needs some cleverness applied. 413 * For now, I'm doing the minimum applicable to actually 414 * get the thing to work. 415 * Wear-levelling and other clever stuff needs to be implemented 416 * and we also need to do some assessment of the results when 417 * the system loses power half-way through the routine. 418 */ 419 u16 LongestChain = 0; 420 u16 ChainLength = 0, thislen; 421 u16 chain, EUN; 422 423 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p," 424 "pending=%d)\n", inftl, pendingblock); 425 426 for (chain = 0; chain < inftl->nb_blocks; chain++) { 427 EUN = inftl->VUtable[chain]; 428 thislen = 0; 429 430 while (EUN <= inftl->lastEUN) { 431 thislen++; 432 EUN = inftl->PUtable[EUN]; 433 if (thislen > 0xff00) { 434 printk(KERN_WARNING "INFTL: endless loop in " 435 "Virtual Chain %d: Unit %x\n", 436 chain, EUN); 437 /* 438 * Actually, don't return failure. 439 * Just ignore this chain and get on with it. 440 */ 441 thislen = 0; 442 break; 443 } 444 } 445 446 if (thislen > ChainLength) { 447 ChainLength = thislen; 448 LongestChain = chain; 449 } 450 } 451 452 if (ChainLength < 2) { 453 printk(KERN_WARNING "INFTL: no Virtual Unit Chains available " 454 "for folding. Failing request\n"); 455 return BLOCK_NIL; 456 } 457 458 return INFTL_foldchain(inftl, LongestChain, pendingblock); 459 } 460 461 static int nrbits(unsigned int val, int bitcount) 462 { 463 int i, total = 0; 464 465 for (i = 0; (i < bitcount); i++) 466 total += (((0x1 << i) & val) ? 1 : 0); 467 return total; 468 } 469 470 /* 471 * INFTL_findwriteunit: Return the unit number into which we can write 472 * for this block. Make it available if it isn't already. 473 */ 474 static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) 475 { 476 unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE); 477 unsigned int thisEUN, writeEUN, prev_block, status; 478 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1); 479 struct mtd_info *mtd = inftl->mbd.mtd; 480 struct inftl_oob oob; 481 struct inftl_bci bci; 482 unsigned char anac, nacs, parity; 483 size_t retlen; 484 int silly, silly2 = 3; 485 486 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p," 487 "block=%d)\n", inftl, block); 488 489 do { 490 /* 491 * Scan the media to find a unit in the VUC which has 492 * a free space for the block in question. 493 */ 494 writeEUN = BLOCK_NIL; 495 thisEUN = inftl->VUtable[thisVUC]; 496 silly = MAX_LOOPS; 497 498 while (thisEUN <= inftl->lastEUN) { 499 inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + 500 blockofs, 8, &retlen, (char *)&bci); 501 502 status = bci.Status | bci.Status1; 503 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " 504 "EUN %d is %x\n", block , writeEUN, status); 505 506 switch(status) { 507 case SECTOR_FREE: 508 writeEUN = thisEUN; 509 break; 510 case SECTOR_DELETED: 511 case SECTOR_USED: 512 /* Can't go any further */ 513 goto hitused; 514 case SECTOR_IGNORE: 515 break; 516 default: 517 /* 518 * Invalid block. Don't use it any more. 519 * Must implement. 520 */ 521 break; 522 } 523 524 if (!silly--) { 525 printk(KERN_WARNING "INFTL: infinite loop in " 526 "Virtual Unit Chain 0x%x\n", thisVUC); 527 return 0xffff; 528 } 529 530 /* Skip to next block in chain */ 531 thisEUN = inftl->PUtable[thisEUN]; 532 } 533 534 hitused: 535 if (writeEUN != BLOCK_NIL) 536 return writeEUN; 537 538 539 /* 540 * OK. We didn't find one in the existing chain, or there 541 * is no existing chain. Allocate a new one. 542 */ 543 writeEUN = INFTL_findfreeblock(inftl, 0); 544 545 if (writeEUN == BLOCK_NIL) { 546 /* 547 * That didn't work - there were no free blocks just 548 * waiting to be picked up. We're going to have to fold 549 * a chain to make room. 550 */ 551 thisEUN = INFTL_makefreeblock(inftl, 0xffff); 552 553 /* 554 * Hopefully we free something, lets try again. 555 * This time we are desperate... 556 */ 557 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 " 558 "to find free EUN to accommodate write to " 559 "VUC %d\n", thisVUC); 560 writeEUN = INFTL_findfreeblock(inftl, 1); 561 if (writeEUN == BLOCK_NIL) { 562 /* 563 * Ouch. This should never happen - we should 564 * always be able to make some room somehow. 565 * If we get here, we've allocated more storage 566 * space than actual media, or our makefreeblock 567 * routine is missing something. 568 */ 569 printk(KERN_WARNING "INFTL: cannot make free " 570 "space.\n"); 571 #ifdef DEBUG 572 INFTL_dumptables(inftl); 573 INFTL_dumpVUchains(inftl); 574 #endif 575 return BLOCK_NIL; 576 } 577 } 578 579 /* 580 * Insert new block into virtual chain. Firstly update the 581 * block headers in flash... 582 */ 583 anac = 0; 584 nacs = 0; 585 thisEUN = inftl->VUtable[thisVUC]; 586 if (thisEUN != BLOCK_NIL) { 587 inftl_read_oob(mtd, thisEUN * inftl->EraseSize 588 + 8, 8, &retlen, (char *)&oob.u); 589 anac = oob.u.a.ANAC + 1; 590 nacs = oob.u.a.NACs + 1; 591 } 592 593 prev_block = inftl->VUtable[thisVUC]; 594 if (prev_block < inftl->nb_blocks) 595 prev_block -= inftl->firstEUN; 596 597 parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0; 598 parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; 599 parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; 600 parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; 601 602 oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); 603 oob.u.a.prevUnitNo = cpu_to_le16(prev_block); 604 oob.u.a.ANAC = anac; 605 oob.u.a.NACs = nacs; 606 oob.u.a.parityPerField = parity; 607 oob.u.a.discarded = 0xaa; 608 609 inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8, 610 &retlen, (char *)&oob.u); 611 612 /* Also back up header... */ 613 oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC); 614 oob.u.b.prevUnitNo = cpu_to_le16(prev_block); 615 oob.u.b.ANAC = anac; 616 oob.u.b.NACs = nacs; 617 oob.u.b.parityPerField = parity; 618 oob.u.b.discarded = 0xaa; 619 620 inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 621 SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); 622 623 inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; 624 inftl->VUtable[thisVUC] = writeEUN; 625 626 inftl->numfreeEUNs--; 627 return writeEUN; 628 629 } while (silly2--); 630 631 printk(KERN_WARNING "INFTL: error folding to make room for Virtual " 632 "Unit Chain 0x%x\n", thisVUC); 633 return 0xffff; 634 } 635 636 /* 637 * Given a Virtual Unit Chain, see if it can be deleted, and if so do it. 638 */ 639 static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) 640 { 641 struct mtd_info *mtd = inftl->mbd.mtd; 642 unsigned char BlockUsed[MAX_SECTORS_PER_UNIT]; 643 unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT]; 644 unsigned int thisEUN, status; 645 int block, silly; 646 struct inftl_bci bci; 647 size_t retlen; 648 649 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p," 650 "thisVUC=%d)\n", inftl, thisVUC); 651 652 memset(BlockUsed, 0, sizeof(BlockUsed)); 653 memset(BlockDeleted, 0, sizeof(BlockDeleted)); 654 655 thisEUN = inftl->VUtable[thisVUC]; 656 if (thisEUN == BLOCK_NIL) { 657 printk(KERN_WARNING "INFTL: trying to delete non-existent " 658 "Virtual Unit Chain %d!\n", thisVUC); 659 return; 660 } 661 662 /* 663 * Scan through the Erase Units to determine whether any data is in 664 * each of the 512-byte blocks within the Chain. 665 */ 666 silly = MAX_LOOPS; 667 while (thisEUN < inftl->nb_blocks) { 668 for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) { 669 if (BlockUsed[block] || BlockDeleted[block]) 670 continue; 671 672 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) 673 + (block * SECTORSIZE), 8 , &retlen, 674 (char *)&bci) < 0) 675 status = SECTOR_IGNORE; 676 else 677 status = bci.Status | bci.Status1; 678 679 switch(status) { 680 case SECTOR_FREE: 681 case SECTOR_IGNORE: 682 break; 683 case SECTOR_USED: 684 BlockUsed[block] = 1; 685 continue; 686 case SECTOR_DELETED: 687 BlockDeleted[block] = 1; 688 continue; 689 default: 690 printk(KERN_WARNING "INFTL: unknown status " 691 "for block %d in EUN %d: 0x%x\n", 692 block, thisEUN, status); 693 } 694 } 695 696 if (!silly--) { 697 printk(KERN_WARNING "INFTL: infinite loop in Virtual " 698 "Unit Chain 0x%x\n", thisVUC); 699 return; 700 } 701 702 thisEUN = inftl->PUtable[thisEUN]; 703 } 704 705 for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) 706 if (BlockUsed[block]) 707 return; 708 709 /* 710 * For each block in the chain free it and make it available 711 * for future use. Erase from the oldest unit first. 712 */ 713 DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC); 714 715 for (;;) { 716 u16 *prevEUN = &inftl->VUtable[thisVUC]; 717 thisEUN = *prevEUN; 718 719 /* If the chain is all gone already, we're done */ 720 if (thisEUN == BLOCK_NIL) { 721 DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); 722 return; 723 } 724 725 /* Find oldest unit in chain. */ 726 while (inftl->PUtable[thisEUN] != BLOCK_NIL) { 727 BUG_ON(thisEUN >= inftl->nb_blocks); 728 729 prevEUN = &inftl->PUtable[thisEUN]; 730 thisEUN = *prevEUN; 731 } 732 733 DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", 734 thisEUN, thisVUC); 735 736 if (INFTL_formatblock(inftl, thisEUN) < 0) { 737 /* 738 * Could not erase : mark block as reserved. 739 */ 740 inftl->PUtable[thisEUN] = BLOCK_RESERVED; 741 } else { 742 /* Correctly erased : mark it as free */ 743 inftl->PUtable[thisEUN] = BLOCK_FREE; 744 inftl->numfreeEUNs++; 745 } 746 747 /* Now sort out whatever was pointing to it... */ 748 *prevEUN = BLOCK_NIL; 749 750 /* Ideally we'd actually be responsive to new 751 requests while we're doing this -- if there's 752 free space why should others be made to wait? */ 753 cond_resched(); 754 } 755 756 inftl->VUtable[thisVUC] = BLOCK_NIL; 757 } 758 759 static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) 760 { 761 unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; 762 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); 763 struct mtd_info *mtd = inftl->mbd.mtd; 764 unsigned int status; 765 int silly = MAX_LOOPS; 766 size_t retlen; 767 struct inftl_bci bci; 768 769 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p," 770 "block=%d)\n", inftl, block); 771 772 while (thisEUN < inftl->nb_blocks) { 773 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + 774 blockofs, 8, &retlen, (char *)&bci) < 0) 775 status = SECTOR_IGNORE; 776 else 777 status = bci.Status | bci.Status1; 778 779 switch (status) { 780 case SECTOR_FREE: 781 case SECTOR_IGNORE: 782 break; 783 case SECTOR_DELETED: 784 thisEUN = BLOCK_NIL; 785 goto foundit; 786 case SECTOR_USED: 787 goto foundit; 788 default: 789 printk(KERN_WARNING "INFTL: unknown status for " 790 "block %d in EUN %d: 0x%x\n", 791 block, thisEUN, status); 792 break; 793 } 794 795 if (!silly--) { 796 printk(KERN_WARNING "INFTL: infinite loop in Virtual " 797 "Unit Chain 0x%x\n", 798 block / (inftl->EraseSize / SECTORSIZE)); 799 return 1; 800 } 801 thisEUN = inftl->PUtable[thisEUN]; 802 } 803 804 foundit: 805 if (thisEUN != BLOCK_NIL) { 806 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; 807 808 if (inftl_read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0) 809 return -EIO; 810 bci.Status = bci.Status1 = SECTOR_DELETED; 811 if (inftl_write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0) 812 return -EIO; 813 INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE)); 814 } 815 return 0; 816 } 817 818 static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, 819 char *buffer) 820 { 821 struct INFTLrecord *inftl = (void *)mbd; 822 unsigned int writeEUN; 823 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); 824 size_t retlen; 825 struct inftl_oob oob; 826 char *p, *pend; 827 828 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld," 829 "buffer=%p)\n", inftl, block, buffer); 830 831 /* Is block all zero? */ 832 pend = buffer + SECTORSIZE; 833 for (p = buffer; p < pend && !*p; p++) 834 ; 835 836 if (p < pend) { 837 writeEUN = INFTL_findwriteunit(inftl, block); 838 839 if (writeEUN == BLOCK_NIL) { 840 printk(KERN_WARNING "inftl_writeblock(): cannot find " 841 "block to write to\n"); 842 /* 843 * If we _still_ haven't got a block to use, 844 * we're screwed. 845 */ 846 return 1; 847 } 848 849 memset(&oob, 0xff, sizeof(struct inftl_oob)); 850 oob.b.Status = oob.b.Status1 = SECTOR_USED; 851 852 inftl_write(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) + 853 blockofs, SECTORSIZE, &retlen, (char *)buffer, 854 (char *)&oob); 855 /* 856 * need to write SECTOR_USED flags since they are not written 857 * in mtd_writeecc 858 */ 859 } else { 860 INFTL_deleteblock(inftl, block); 861 } 862 863 return 0; 864 } 865 866 static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, 867 char *buffer) 868 { 869 struct INFTLrecord *inftl = (void *)mbd; 870 unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; 871 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); 872 struct mtd_info *mtd = inftl->mbd.mtd; 873 unsigned int status; 874 int silly = MAX_LOOPS; 875 struct inftl_bci bci; 876 size_t retlen; 877 878 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," 879 "buffer=%p)\n", inftl, block, buffer); 880 881 while (thisEUN < inftl->nb_blocks) { 882 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + 883 blockofs, 8, &retlen, (char *)&bci) < 0) 884 status = SECTOR_IGNORE; 885 else 886 status = bci.Status | bci.Status1; 887 888 switch (status) { 889 case SECTOR_DELETED: 890 thisEUN = BLOCK_NIL; 891 goto foundit; 892 case SECTOR_USED: 893 goto foundit; 894 case SECTOR_FREE: 895 case SECTOR_IGNORE: 896 break; 897 default: 898 printk(KERN_WARNING "INFTL: unknown status for " 899 "block %ld in EUN %d: 0x%04x\n", 900 block, thisEUN, status); 901 break; 902 } 903 904 if (!silly--) { 905 printk(KERN_WARNING "INFTL: infinite loop in " 906 "Virtual Unit Chain 0x%lx\n", 907 block / (inftl->EraseSize / SECTORSIZE)); 908 return 1; 909 } 910 911 thisEUN = inftl->PUtable[thisEUN]; 912 } 913 914 foundit: 915 if (thisEUN == BLOCK_NIL) { 916 /* The requested block is not on the media, return all 0x00 */ 917 memset(buffer, 0, SECTORSIZE); 918 } else { 919 size_t retlen; 920 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; 921 int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer); 922 923 /* Handle corrected bit flips gracefully */ 924 if (ret < 0 && ret != -EUCLEAN) 925 return -EIO; 926 } 927 return 0; 928 } 929 930 static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) 931 { 932 struct INFTLrecord *inftl = (void *)dev; 933 934 geo->heads = inftl->heads; 935 geo->sectors = inftl->sectors; 936 geo->cylinders = inftl->cylinders; 937 938 return 0; 939 } 940 941 static struct mtd_blktrans_ops inftl_tr = { 942 .name = "inftl", 943 .major = INFTL_MAJOR, 944 .part_bits = INFTL_PARTN_BITS, 945 .blksize = 512, 946 .getgeo = inftl_getgeo, 947 .readsect = inftl_readblock, 948 .writesect = inftl_writeblock, 949 .add_mtd = inftl_add_mtd, 950 .remove_dev = inftl_remove_dev, 951 .owner = THIS_MODULE, 952 }; 953 954 static int __init init_inftl(void) 955 { 956 printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " 957 "inftlmount.c %s\n", inftlmountrev); 958 959 return register_mtd_blktrans(&inftl_tr); 960 } 961 962 static void __exit cleanup_inftl(void) 963 { 964 deregister_mtd_blktrans(&inftl_tr); 965 } 966 967 module_init(init_inftl); 968 module_exit(cleanup_inftl); 969 970 MODULE_LICENSE("GPL"); 971 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al."); 972 MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus"); 973