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