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