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