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