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