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