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