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 <linux/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_is_nand(mtd) || 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, 347 (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), 348 SECTORSIZE, 349 &retlen, 350 movebuf); 351 if (ret < 0 && !mtd_is_bitflip(ret)) { 352 ret = mtd_read(mtd, 353 (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), 354 SECTORSIZE, 355 &retlen, 356 movebuf); 357 if (ret != -EIO) 358 pr_debug("INFTL: error went away on retry?\n"); 359 } 360 memset(&oob, 0xff, sizeof(struct inftl_oob)); 361 oob.b.Status = oob.b.Status1 = SECTOR_USED; 362 363 inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) + 364 (block * SECTORSIZE), SECTORSIZE, &retlen, 365 movebuf, (char *)&oob); 366 } 367 368 /* 369 * Newest unit in chain now contains data from _all_ older units. 370 * So go through and erase each unit in chain, oldest first. (This 371 * is important, by doing oldest first if we crash/reboot then it 372 * it is relatively simple to clean up the mess). 373 */ 374 pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC); 375 376 for (;;) { 377 /* Find oldest unit in chain. */ 378 thisEUN = inftl->VUtable[thisVUC]; 379 prevEUN = BLOCK_NIL; 380 while (inftl->PUtable[thisEUN] != BLOCK_NIL) { 381 prevEUN = thisEUN; 382 thisEUN = inftl->PUtable[thisEUN]; 383 } 384 385 /* Check if we are all done */ 386 if (thisEUN == targetEUN) 387 break; 388 389 /* Unlink the last block from the chain. */ 390 inftl->PUtable[prevEUN] = BLOCK_NIL; 391 392 /* Now try to erase it. */ 393 if (INFTL_formatblock(inftl, thisEUN) < 0) { 394 /* 395 * Could not erase : mark block as reserved. 396 */ 397 inftl->PUtable[thisEUN] = BLOCK_RESERVED; 398 } else { 399 /* Correctly erased : mark it as free */ 400 inftl->PUtable[thisEUN] = BLOCK_FREE; 401 inftl->numfreeEUNs++; 402 } 403 } 404 405 return targetEUN; 406 } 407 408 static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) 409 { 410 /* 411 * This is the part that needs some cleverness applied. 412 * For now, I'm doing the minimum applicable to actually 413 * get the thing to work. 414 * Wear-levelling and other clever stuff needs to be implemented 415 * and we also need to do some assessment of the results when 416 * the system loses power half-way through the routine. 417 */ 418 u16 LongestChain = 0; 419 u16 ChainLength = 0, thislen; 420 u16 chain, EUN; 421 422 pr_debug("INFTL: INFTL_makefreeblock(inftl=%p," 423 "pending=%d)\n", inftl, pendingblock); 424 425 for (chain = 0; chain < inftl->nb_blocks; chain++) { 426 EUN = inftl->VUtable[chain]; 427 thislen = 0; 428 429 while (EUN <= inftl->lastEUN) { 430 thislen++; 431 EUN = inftl->PUtable[EUN]; 432 if (thislen > 0xff00) { 433 printk(KERN_WARNING "INFTL: endless loop in " 434 "Virtual Chain %d: Unit %x\n", 435 chain, EUN); 436 /* 437 * Actually, don't return failure. 438 * Just ignore this chain and get on with it. 439 */ 440 thislen = 0; 441 break; 442 } 443 } 444 445 if (thislen > ChainLength) { 446 ChainLength = thislen; 447 LongestChain = chain; 448 } 449 } 450 451 if (ChainLength < 2) { 452 printk(KERN_WARNING "INFTL: no Virtual Unit Chains available " 453 "for folding. Failing request\n"); 454 return BLOCK_NIL; 455 } 456 457 return INFTL_foldchain(inftl, LongestChain, pendingblock); 458 } 459 460 static int nrbits(unsigned int val, int bitcount) 461 { 462 int i, total = 0; 463 464 for (i = 0; (i < bitcount); i++) 465 total += (((0x1 << i) & val) ? 1 : 0); 466 return total; 467 } 468 469 /* 470 * INFTL_findwriteunit: Return the unit number into which we can write 471 * for this block. Make it available if it isn't already. 472 */ 473 static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) 474 { 475 unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE); 476 unsigned int thisEUN, writeEUN, prev_block, status; 477 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1); 478 struct mtd_info *mtd = inftl->mbd.mtd; 479 struct inftl_oob oob; 480 struct inftl_bci bci; 481 unsigned char anac, nacs, parity; 482 size_t retlen; 483 int silly, silly2 = 3; 484 485 pr_debug("INFTL: INFTL_findwriteunit(inftl=%p,block=%d)\n", 486 inftl, block); 487 488 do { 489 /* 490 * Scan the media to find a unit in the VUC which has 491 * a free space for the block in question. 492 */ 493 writeEUN = BLOCK_NIL; 494 thisEUN = inftl->VUtable[thisVUC]; 495 silly = MAX_LOOPS; 496 497 while (thisEUN <= inftl->lastEUN) { 498 inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + 499 blockofs, 8, &retlen, (char *)&bci); 500 501 status = bci.Status | bci.Status1; 502 pr_debug("INFTL: status of block %d in EUN %d is %x\n", 503 block , writeEUN, status); 504 505 switch(status) { 506 case SECTOR_FREE: 507 writeEUN = thisEUN; 508 break; 509 case SECTOR_DELETED: 510 case SECTOR_USED: 511 /* Can't go any further */ 512 goto hitused; 513 case SECTOR_IGNORE: 514 break; 515 default: 516 /* 517 * Invalid block. Don't use it any more. 518 * Must implement. 519 */ 520 break; 521 } 522 523 if (!silly--) { 524 printk(KERN_WARNING "INFTL: infinite loop in " 525 "Virtual Unit Chain 0x%x\n", thisVUC); 526 return BLOCK_NIL; 527 } 528 529 /* Skip to next block in chain */ 530 thisEUN = inftl->PUtable[thisEUN]; 531 } 532 533 hitused: 534 if (writeEUN != BLOCK_NIL) 535 return writeEUN; 536 537 538 /* 539 * OK. We didn't find one in the existing chain, or there 540 * is no existing chain. Allocate a new one. 541 */ 542 writeEUN = INFTL_findfreeblock(inftl, 0); 543 544 if (writeEUN == BLOCK_NIL) { 545 /* 546 * That didn't work - there were no free blocks just 547 * waiting to be picked up. We're going to have to fold 548 * a chain to make room. 549 */ 550 thisEUN = INFTL_makefreeblock(inftl, block); 551 552 /* 553 * Hopefully we free something, lets try again. 554 * This time we are desperate... 555 */ 556 pr_debug("INFTL: using desperate==1 to find free EUN " 557 "to accommodate write to VUC %d\n", 558 thisVUC); 559 writeEUN = INFTL_findfreeblock(inftl, 1); 560 if (writeEUN == BLOCK_NIL) { 561 /* 562 * Ouch. This should never happen - we should 563 * always be able to make some room somehow. 564 * If we get here, we've allocated more storage 565 * space than actual media, or our makefreeblock 566 * routine is missing something. 567 */ 568 printk(KERN_WARNING "INFTL: cannot make free " 569 "space.\n"); 570 #ifdef DEBUG 571 INFTL_dumptables(inftl); 572 INFTL_dumpVUchains(inftl); 573 #endif 574 return BLOCK_NIL; 575 } 576 } 577 578 /* 579 * Insert new block into virtual chain. Firstly update the 580 * block headers in flash... 581 */ 582 anac = 0; 583 nacs = 0; 584 thisEUN = inftl->VUtable[thisVUC]; 585 if (thisEUN != BLOCK_NIL) { 586 inftl_read_oob(mtd, thisEUN * inftl->EraseSize 587 + 8, 8, &retlen, (char *)&oob.u); 588 anac = oob.u.a.ANAC + 1; 589 nacs = oob.u.a.NACs + 1; 590 } 591 592 prev_block = inftl->VUtable[thisVUC]; 593 if (prev_block < inftl->nb_blocks) 594 prev_block -= inftl->firstEUN; 595 596 parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0; 597 parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; 598 parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; 599 parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; 600 601 oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); 602 oob.u.a.prevUnitNo = cpu_to_le16(prev_block); 603 oob.u.a.ANAC = anac; 604 oob.u.a.NACs = nacs; 605 oob.u.a.parityPerField = parity; 606 oob.u.a.discarded = 0xaa; 607 608 inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8, 609 &retlen, (char *)&oob.u); 610 611 /* Also back up header... */ 612 oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC); 613 oob.u.b.prevUnitNo = cpu_to_le16(prev_block); 614 oob.u.b.ANAC = anac; 615 oob.u.b.NACs = nacs; 616 oob.u.b.parityPerField = parity; 617 oob.u.b.discarded = 0xaa; 618 619 inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 620 SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); 621 622 inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; 623 inftl->VUtable[thisVUC] = writeEUN; 624 625 inftl->numfreeEUNs--; 626 return writeEUN; 627 628 } while (silly2--); 629 630 printk(KERN_WARNING "INFTL: error folding to make room for Virtual " 631 "Unit Chain 0x%x\n", thisVUC); 632 return BLOCK_NIL; 633 } 634 635 /* 636 * Given a Virtual Unit Chain, see if it can be deleted, and if so do it. 637 */ 638 static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) 639 { 640 struct mtd_info *mtd = inftl->mbd.mtd; 641 unsigned char BlockUsed[MAX_SECTORS_PER_UNIT]; 642 unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT]; 643 unsigned int thisEUN, status; 644 int block, silly; 645 struct inftl_bci bci; 646 size_t retlen; 647 648 pr_debug("INFTL: INFTL_trydeletechain(inftl=%p," 649 "thisVUC=%d)\n", inftl, thisVUC); 650 651 memset(BlockUsed, 0, sizeof(BlockUsed)); 652 memset(BlockDeleted, 0, sizeof(BlockDeleted)); 653 654 thisEUN = inftl->VUtable[thisVUC]; 655 if (thisEUN == BLOCK_NIL) { 656 printk(KERN_WARNING "INFTL: trying to delete non-existent " 657 "Virtual Unit Chain %d!\n", thisVUC); 658 return; 659 } 660 661 /* 662 * Scan through the Erase Units to determine whether any data is in 663 * each of the 512-byte blocks within the Chain. 664 */ 665 silly = MAX_LOOPS; 666 while (thisEUN < inftl->nb_blocks) { 667 for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) { 668 if (BlockUsed[block] || BlockDeleted[block]) 669 continue; 670 671 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) 672 + (block * SECTORSIZE), 8 , &retlen, 673 (char *)&bci) < 0) 674 status = SECTOR_IGNORE; 675 else 676 status = bci.Status | bci.Status1; 677 678 switch(status) { 679 case SECTOR_FREE: 680 case SECTOR_IGNORE: 681 break; 682 case SECTOR_USED: 683 BlockUsed[block] = 1; 684 continue; 685 case SECTOR_DELETED: 686 BlockDeleted[block] = 1; 687 continue; 688 default: 689 printk(KERN_WARNING "INFTL: unknown status " 690 "for block %d in EUN %d: 0x%x\n", 691 block, thisEUN, status); 692 } 693 } 694 695 if (!silly--) { 696 printk(KERN_WARNING "INFTL: infinite loop in Virtual " 697 "Unit Chain 0x%x\n", thisVUC); 698 return; 699 } 700 701 thisEUN = inftl->PUtable[thisEUN]; 702 } 703 704 for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) 705 if (BlockUsed[block]) 706 return; 707 708 /* 709 * For each block in the chain free it and make it available 710 * for future use. Erase from the oldest unit first. 711 */ 712 pr_debug("INFTL: deleting empty VUC %d\n", thisVUC); 713 714 for (;;) { 715 u16 *prevEUN = &inftl->VUtable[thisVUC]; 716 thisEUN = *prevEUN; 717 718 /* If the chain is all gone already, we're done */ 719 if (thisEUN == BLOCK_NIL) { 720 pr_debug("INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); 721 return; 722 } 723 724 /* Find oldest unit in chain. */ 725 while (inftl->PUtable[thisEUN] != BLOCK_NIL) { 726 BUG_ON(thisEUN >= inftl->nb_blocks); 727 728 prevEUN = &inftl->PUtable[thisEUN]; 729 thisEUN = *prevEUN; 730 } 731 732 pr_debug("Deleting EUN %d from VUC %d\n", 733 thisEUN, thisVUC); 734 735 if (INFTL_formatblock(inftl, thisEUN) < 0) { 736 /* 737 * Could not erase : mark block as reserved. 738 */ 739 inftl->PUtable[thisEUN] = BLOCK_RESERVED; 740 } else { 741 /* Correctly erased : mark it as free */ 742 inftl->PUtable[thisEUN] = BLOCK_FREE; 743 inftl->numfreeEUNs++; 744 } 745 746 /* Now sort out whatever was pointing to it... */ 747 *prevEUN = BLOCK_NIL; 748 749 /* Ideally we'd actually be responsive to new 750 requests while we're doing this -- if there's 751 free space why should others be made to wait? */ 752 cond_resched(); 753 } 754 755 inftl->VUtable[thisVUC] = BLOCK_NIL; 756 } 757 758 static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) 759 { 760 unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; 761 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); 762 struct mtd_info *mtd = inftl->mbd.mtd; 763 unsigned int status; 764 int silly = MAX_LOOPS; 765 size_t retlen; 766 struct inftl_bci bci; 767 768 pr_debug("INFTL: INFTL_deleteblock(inftl=%p," 769 "block=%d)\n", inftl, block); 770 771 while (thisEUN < inftl->nb_blocks) { 772 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + 773 blockofs, 8, &retlen, (char *)&bci) < 0) 774 status = SECTOR_IGNORE; 775 else 776 status = bci.Status | bci.Status1; 777 778 switch (status) { 779 case SECTOR_FREE: 780 case SECTOR_IGNORE: 781 break; 782 case SECTOR_DELETED: 783 thisEUN = BLOCK_NIL; 784 goto foundit; 785 case SECTOR_USED: 786 goto foundit; 787 default: 788 printk(KERN_WARNING "INFTL: unknown status for " 789 "block %d in EUN %d: 0x%x\n", 790 block, thisEUN, status); 791 break; 792 } 793 794 if (!silly--) { 795 printk(KERN_WARNING "INFTL: infinite loop in Virtual " 796 "Unit Chain 0x%x\n", 797 block / (inftl->EraseSize / SECTORSIZE)); 798 return 1; 799 } 800 thisEUN = inftl->PUtable[thisEUN]; 801 } 802 803 foundit: 804 if (thisEUN != BLOCK_NIL) { 805 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; 806 807 if (inftl_read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0) 808 return -EIO; 809 bci.Status = bci.Status1 = SECTOR_DELETED; 810 if (inftl_write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0) 811 return -EIO; 812 INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE)); 813 } 814 return 0; 815 } 816 817 static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, 818 char *buffer) 819 { 820 struct INFTLrecord *inftl = (void *)mbd; 821 unsigned int writeEUN; 822 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); 823 size_t retlen; 824 struct inftl_oob oob; 825 char *p, *pend; 826 827 pr_debug("INFTL: inftl_writeblock(inftl=%p,block=%ld," 828 "buffer=%p)\n", inftl, block, buffer); 829 830 /* Is block all zero? */ 831 pend = buffer + SECTORSIZE; 832 for (p = buffer; p < pend && !*p; p++) 833 ; 834 835 if (p < pend) { 836 writeEUN = INFTL_findwriteunit(inftl, block); 837 838 if (writeEUN == BLOCK_NIL) { 839 printk(KERN_WARNING "inftl_writeblock(): cannot find " 840 "block to write to\n"); 841 /* 842 * If we _still_ haven't got a block to use, 843 * we're screwed. 844 */ 845 return 1; 846 } 847 848 memset(&oob, 0xff, sizeof(struct inftl_oob)); 849 oob.b.Status = oob.b.Status1 = SECTOR_USED; 850 851 inftl_write(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) + 852 blockofs, SECTORSIZE, &retlen, (char *)buffer, 853 (char *)&oob); 854 /* 855 * need to write SECTOR_USED flags since they are not written 856 * in mtd_writeecc 857 */ 858 } else { 859 INFTL_deleteblock(inftl, block); 860 } 861 862 return 0; 863 } 864 865 static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, 866 char *buffer) 867 { 868 struct INFTLrecord *inftl = (void *)mbd; 869 unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; 870 unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); 871 struct mtd_info *mtd = inftl->mbd.mtd; 872 unsigned int status; 873 int silly = MAX_LOOPS; 874 struct inftl_bci bci; 875 size_t retlen; 876 877 pr_debug("INFTL: inftl_readblock(inftl=%p,block=%ld," 878 "buffer=%p)\n", inftl, block, buffer); 879 880 while (thisEUN < inftl->nb_blocks) { 881 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) + 882 blockofs, 8, &retlen, (char *)&bci) < 0) 883 status = SECTOR_IGNORE; 884 else 885 status = bci.Status | bci.Status1; 886 887 switch (status) { 888 case SECTOR_DELETED: 889 thisEUN = BLOCK_NIL; 890 goto foundit; 891 case SECTOR_USED: 892 goto foundit; 893 case SECTOR_FREE: 894 case SECTOR_IGNORE: 895 break; 896 default: 897 printk(KERN_WARNING "INFTL: unknown status for " 898 "block %ld in EUN %d: 0x%04x\n", 899 block, thisEUN, status); 900 break; 901 } 902 903 if (!silly--) { 904 printk(KERN_WARNING "INFTL: infinite loop in " 905 "Virtual Unit Chain 0x%lx\n", 906 block / (inftl->EraseSize / SECTORSIZE)); 907 return 1; 908 } 909 910 thisEUN = inftl->PUtable[thisEUN]; 911 } 912 913 foundit: 914 if (thisEUN == BLOCK_NIL) { 915 /* The requested block is not on the media, return all 0x00 */ 916 memset(buffer, 0, SECTORSIZE); 917 } else { 918 size_t retlen; 919 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; 920 int ret = mtd_read(mtd, ptr, SECTORSIZE, &retlen, buffer); 921 922 /* Handle corrected bit flips gracefully */ 923 if (ret < 0 && !mtd_is_bitflip(ret)) 924 return -EIO; 925 } 926 return 0; 927 } 928 929 static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) 930 { 931 struct INFTLrecord *inftl = (void *)dev; 932 933 geo->heads = inftl->heads; 934 geo->sectors = inftl->sectors; 935 geo->cylinders = inftl->cylinders; 936 937 return 0; 938 } 939 940 static struct mtd_blktrans_ops inftl_tr = { 941 .name = "inftl", 942 .major = INFTL_MAJOR, 943 .part_bits = INFTL_PARTN_BITS, 944 .blksize = 512, 945 .getgeo = inftl_getgeo, 946 .readsect = inftl_readblock, 947 .writesect = inftl_writeblock, 948 .add_mtd = inftl_add_mtd, 949 .remove_dev = inftl_remove_dev, 950 .owner = THIS_MODULE, 951 }; 952 953 static int __init init_inftl(void) 954 { 955 return register_mtd_blktrans(&inftl_tr); 956 } 957 958 static void __exit cleanup_inftl(void) 959 { 960 deregister_mtd_blktrans(&inftl_tr); 961 } 962 963 module_init(init_inftl); 964 module_exit(cleanup_inftl); 965 966 MODULE_LICENSE("GPL"); 967 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al."); 968 MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus"); 969