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