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