1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Linux driver for NAND Flash Translation Layer 4 * 5 * Copyright © 1999 Machine Vision Holdings, Inc. 6 * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> 7 */ 8 9 #define PRERELEASE 10 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <asm/errno.h> 14 #include <asm/io.h> 15 #include <linux/uaccess.h> 16 #include <linux/delay.h> 17 #include <linux/slab.h> 18 #include <linux/init.h> 19 #include <linux/hdreg.h> 20 #include <linux/blkdev.h> 21 22 #include <linux/kmod.h> 23 #include <linux/mtd/mtd.h> 24 #include <linux/mtd/rawnand.h> 25 #include <linux/mtd/nftl.h> 26 #include <linux/mtd/blktrans.h> 27 28 /* maximum number of loops while examining next block, to have a 29 chance to detect consistency problems (they should never happen 30 because of the checks done in the mounting */ 31 32 #define MAX_LOOPS 10000 33 34 35 static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) 36 { 37 struct NFTLrecord *nftl; 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 pr_debug("NFTL: add_mtd for %s\n", mtd->name); 47 48 nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL); 49 50 if (!nftl) 51 return; 52 53 nftl->mbd.mtd = mtd; 54 nftl->mbd.devnum = -1; 55 56 nftl->mbd.tr = tr; 57 58 if (NFTL_mount(nftl) < 0) { 59 printk(KERN_WARNING "NFTL: could not mount device\n"); 60 kfree(nftl); 61 return; 62 } 63 64 /* OK, it's a new one. Set up all the data structures. */ 65 66 /* Calculate geometry */ 67 nftl->cylinders = 1024; 68 nftl->heads = 16; 69 70 temp = nftl->cylinders * nftl->heads; 71 nftl->sectors = nftl->mbd.size / temp; 72 if (nftl->mbd.size % temp) { 73 nftl->sectors++; 74 temp = nftl->cylinders * nftl->sectors; 75 nftl->heads = nftl->mbd.size / temp; 76 77 if (nftl->mbd.size % temp) { 78 nftl->heads++; 79 temp = nftl->heads * nftl->sectors; 80 nftl->cylinders = nftl->mbd.size / temp; 81 } 82 } 83 84 if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { 85 /* 86 Oh no we don't have 87 mbd.size == heads * cylinders * sectors 88 */ 89 printk(KERN_WARNING "NFTL: cannot calculate a geometry to " 90 "match size of 0x%lx.\n", nftl->mbd.size); 91 printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " 92 "(== 0x%lx sects)\n", 93 nftl->cylinders, nftl->heads , nftl->sectors, 94 (long)nftl->cylinders * (long)nftl->heads * 95 (long)nftl->sectors ); 96 } 97 98 if (add_mtd_blktrans_dev(&nftl->mbd)) { 99 kfree(nftl->ReplUnitTable); 100 kfree(nftl->EUNtable); 101 kfree(nftl); 102 return; 103 } 104 #ifdef PSYCHO_DEBUG 105 printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a'); 106 #endif 107 } 108 109 static void nftl_remove_dev(struct mtd_blktrans_dev *dev) 110 { 111 struct NFTLrecord *nftl = (void *)dev; 112 113 pr_debug("NFTL: remove_dev (i=%d)\n", dev->devnum); 114 115 del_mtd_blktrans_dev(dev); 116 kfree(nftl->ReplUnitTable); 117 kfree(nftl->EUNtable); 118 } 119 120 /* 121 * Read oob data from flash 122 */ 123 int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, 124 size_t *retlen, uint8_t *buf) 125 { 126 loff_t mask = mtd->writesize - 1; 127 struct mtd_oob_ops ops = { }; 128 int res; 129 130 ops.mode = MTD_OPS_PLACE_OOB; 131 ops.ooboffs = offs & mask; 132 ops.ooblen = len; 133 ops.oobbuf = buf; 134 ops.datbuf = NULL; 135 136 res = mtd_read_oob(mtd, offs & ~mask, &ops); 137 *retlen = ops.oobretlen; 138 return res; 139 } 140 141 /* 142 * Write oob data to flash 143 */ 144 int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, 145 size_t *retlen, uint8_t *buf) 146 { 147 loff_t mask = mtd->writesize - 1; 148 struct mtd_oob_ops ops = { }; 149 int res; 150 151 ops.mode = MTD_OPS_PLACE_OOB; 152 ops.ooboffs = offs & mask; 153 ops.ooblen = len; 154 ops.oobbuf = buf; 155 ops.datbuf = NULL; 156 157 res = mtd_write_oob(mtd, offs & ~mask, &ops); 158 *retlen = ops.oobretlen; 159 return res; 160 } 161 162 #ifdef CONFIG_NFTL_RW 163 164 /* 165 * Write data and oob to flash 166 */ 167 static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len, 168 size_t *retlen, uint8_t *buf, uint8_t *oob) 169 { 170 loff_t mask = mtd->writesize - 1; 171 struct mtd_oob_ops ops = { }; 172 int res; 173 174 ops.mode = MTD_OPS_PLACE_OOB; 175 ops.ooboffs = offs & mask; 176 ops.ooblen = mtd->oobsize; 177 ops.oobbuf = oob; 178 ops.datbuf = buf; 179 ops.len = len; 180 181 res = mtd_write_oob(mtd, offs & ~mask, &ops); 182 *retlen = ops.retlen; 183 return res; 184 } 185 186 /* Actual NFTL access routines */ 187 /* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used 188 * when the give Virtual Unit Chain 189 */ 190 static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) 191 { 192 /* For a given Virtual Unit Chain: find or create a free block and 193 add it to the chain */ 194 /* We're passed the number of the last EUN in the chain, to save us from 195 having to look it up again */ 196 u16 pot = nftl->LastFreeEUN; 197 int silly = nftl->nb_blocks; 198 199 /* Normally, we force a fold to happen before we run out of free blocks completely */ 200 if (!desperate && nftl->numfreeEUNs < 2) { 201 pr_debug("NFTL_findfreeblock: there are too few free EUNs\n"); 202 return BLOCK_NIL; 203 } 204 205 /* Scan for a free block */ 206 do { 207 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) { 208 nftl->LastFreeEUN = pot; 209 nftl->numfreeEUNs--; 210 return pot; 211 } 212 213 /* This will probably point to the MediaHdr unit itself, 214 right at the beginning of the partition. But that unit 215 (and the backup unit too) should have the UCI set 216 up so that it's not selected for overwriting */ 217 if (++pot > nftl->lastEUN) 218 pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN); 219 220 if (!silly--) { 221 printk("Argh! No free blocks found! LastFreeEUN = %d, " 222 "FirstEUN = %d\n", nftl->LastFreeEUN, 223 le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); 224 return BLOCK_NIL; 225 } 226 } while (pot != nftl->LastFreeEUN); 227 228 return BLOCK_NIL; 229 } 230 231 static noinline_for_stack void NFTL_move_block(struct mtd_info *mtd, loff_t src, loff_t dst) 232 { 233 unsigned char movebuf[512]; 234 struct nftl_oob oob; 235 size_t retlen; 236 int ret; 237 238 ret = mtd_read(mtd, src, 512, &retlen, movebuf); 239 if (ret < 0 && !mtd_is_bitflip(ret)) { 240 ret = mtd_read(mtd, src, 512, &retlen, movebuf); 241 if (ret != -EIO) 242 printk("Error went away on retry.\n"); 243 } 244 memset(&oob, 0xff, sizeof(struct nftl_oob)); 245 oob.b.Status = oob.b.Status1 = SECTOR_USED; 246 247 nftl_write(mtd, dst, 512, &retlen, movebuf, (char *)&oob); 248 } 249 250 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock ) 251 { 252 struct mtd_info *mtd = nftl->mbd.mtd; 253 u16 BlockMap[MAX_SECTORS_PER_UNIT]; 254 unsigned char BlockLastState[MAX_SECTORS_PER_UNIT]; 255 unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT]; 256 unsigned int thisEUN; 257 int block; 258 int silly; 259 unsigned int targetEUN; 260 struct nftl_oob oob; 261 int inplace = 1; 262 size_t retlen; 263 264 memset(BlockMap, 0xff, sizeof(BlockMap)); 265 memset(BlockFreeFound, 0, sizeof(BlockFreeFound)); 266 267 thisEUN = nftl->EUNtable[thisVUC]; 268 269 if (thisEUN == BLOCK_NIL) { 270 printk(KERN_WARNING "Trying to fold non-existent " 271 "Virtual Unit Chain %d!\n", thisVUC); 272 return BLOCK_NIL; 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 targetEUN = BLOCK_NIL; 280 while (thisEUN <= nftl->lastEUN ) { 281 unsigned int status, foldmark; 282 283 targetEUN = thisEUN; 284 for (block = 0; block < nftl->EraseSize / 512; block ++) { 285 nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) + 286 (block * 512), 16 , &retlen, 287 (char *)&oob); 288 if (block == 2) { 289 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; 290 if (foldmark == FOLD_MARK_IN_PROGRESS) { 291 pr_debug("Write Inhibited on EUN %d\n", thisEUN); 292 inplace = 0; 293 } else { 294 /* There's no other reason not to do inplace, 295 except ones that come later. So we don't need 296 to preserve inplace */ 297 inplace = 1; 298 } 299 } 300 status = oob.b.Status | oob.b.Status1; 301 BlockLastState[block] = status; 302 303 switch(status) { 304 case SECTOR_FREE: 305 BlockFreeFound[block] = 1; 306 break; 307 308 case SECTOR_USED: 309 if (!BlockFreeFound[block]) 310 BlockMap[block] = thisEUN; 311 else 312 printk(KERN_WARNING 313 "SECTOR_USED found after SECTOR_FREE " 314 "in Virtual Unit Chain %d for block %d\n", 315 thisVUC, block); 316 break; 317 case SECTOR_DELETED: 318 if (!BlockFreeFound[block]) 319 BlockMap[block] = BLOCK_NIL; 320 else 321 printk(KERN_WARNING 322 "SECTOR_DELETED found after SECTOR_FREE " 323 "in Virtual Unit Chain %d for block %d\n", 324 thisVUC, block); 325 break; 326 327 case SECTOR_IGNORE: 328 break; 329 default: 330 printk("Unknown status for block %d in EUN %d: %x\n", 331 block, thisEUN, status); 332 } 333 } 334 335 if (!silly--) { 336 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", 337 thisVUC); 338 return BLOCK_NIL; 339 } 340 341 thisEUN = nftl->ReplUnitTable[thisEUN]; 342 } 343 344 if (inplace) { 345 /* We're being asked to be a fold-in-place. Check 346 that all blocks which actually have data associated 347 with them (i.e. BlockMap[block] != BLOCK_NIL) are 348 either already present or SECTOR_FREE in the target 349 block. If not, we're going to have to fold out-of-place 350 anyway. 351 */ 352 for (block = 0; block < nftl->EraseSize / 512 ; block++) { 353 if (BlockLastState[block] != SECTOR_FREE && 354 BlockMap[block] != BLOCK_NIL && 355 BlockMap[block] != targetEUN) { 356 pr_debug("Setting inplace to 0. VUC %d, " 357 "block %d was %x lastEUN, " 358 "and is in EUN %d (%s) %d\n", 359 thisVUC, block, BlockLastState[block], 360 BlockMap[block], 361 BlockMap[block]== targetEUN ? "==" : "!=", 362 targetEUN); 363 inplace = 0; 364 break; 365 } 366 } 367 368 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) && 369 pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) && 370 BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] != 371 SECTOR_FREE) { 372 pr_debug("Pending write not free in EUN %d. " 373 "Folding out of place.\n", targetEUN); 374 inplace = 0; 375 } 376 } 377 378 if (!inplace) { 379 pr_debug("Cannot fold Virtual Unit Chain %d in place. " 380 "Trying out-of-place\n", thisVUC); 381 /* We need to find a targetEUN to fold into. */ 382 targetEUN = NFTL_findfreeblock(nftl, 1); 383 if (targetEUN == BLOCK_NIL) { 384 /* Ouch. Now we're screwed. We need to do a 385 fold-in-place of another chain to make room 386 for this one. We need a better way of selecting 387 which chain to fold, because makefreeblock will 388 only ask us to fold the same one again. 389 */ 390 printk(KERN_WARNING 391 "NFTL_findfreeblock(desperate) returns 0xffff.\n"); 392 return BLOCK_NIL; 393 } 394 } else { 395 /* We put a fold mark in the chain we are folding only if we 396 fold in place to help the mount check code. If we do not fold in 397 place, it is possible to find the valid chain by selecting the 398 longer one */ 399 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); 400 oob.u.c.unused = 0xffffffff; 401 nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 402 8, &retlen, (char *)&oob.u); 403 } 404 405 /* OK. We now know the location of every block in the Virtual Unit Chain, 406 and the Erase Unit into which we are supposed to be copying. 407 Go for it. 408 */ 409 pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN); 410 for (block = 0; block < nftl->EraseSize / 512 ; block++) { 411 /* If it's in the target EUN already, or if it's pending write, do nothing */ 412 if (BlockMap[block] == targetEUN || 413 (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) { 414 continue; 415 } 416 417 /* copy only in non free block (free blocks can only 418 happen in case of media errors or deleted blocks) */ 419 if (BlockMap[block] == BLOCK_NIL) 420 continue; 421 422 NFTL_move_block(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 423 (nftl->EraseSize * targetEUN) + (block * 512)); 424 } 425 426 /* add the header so that it is now a valid chain */ 427 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); 428 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL; 429 430 nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8, 431 8, &retlen, (char *)&oob.u); 432 433 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ 434 435 /* At this point, we have two different chains for this Virtual Unit, and no way to tell 436 them apart. If we crash now, we get confused. However, both contain the same data, so we 437 shouldn't actually lose data in this case. It's just that when we load up on a medium which 438 has duplicate chains, we need to free one of the chains because it's not necessary any more. 439 */ 440 thisEUN = nftl->EUNtable[thisVUC]; 441 pr_debug("Want to erase\n"); 442 443 /* For each block in the old chain (except the targetEUN of course), 444 free it and make it available for future use */ 445 while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) { 446 unsigned int EUNtmp; 447 448 EUNtmp = nftl->ReplUnitTable[thisEUN]; 449 450 if (NFTL_formatblock(nftl, thisEUN) < 0) { 451 /* could not erase : mark block as reserved 452 */ 453 nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED; 454 } else { 455 /* correctly erased : mark it as free */ 456 nftl->ReplUnitTable[thisEUN] = BLOCK_FREE; 457 nftl->numfreeEUNs++; 458 } 459 thisEUN = EUNtmp; 460 } 461 462 /* Make this the new start of chain for thisVUC */ 463 nftl->ReplUnitTable[targetEUN] = BLOCK_NIL; 464 nftl->EUNtable[thisVUC] = targetEUN; 465 466 return targetEUN; 467 } 468 469 static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) 470 { 471 /* This is the part that needs some cleverness applied. 472 For now, I'm doing the minimum applicable to actually 473 get the thing to work. 474 Wear-levelling and other clever stuff needs to be implemented 475 and we also need to do some assessment of the results when 476 the system loses power half-way through the routine. 477 */ 478 u16 LongestChain = 0; 479 u16 ChainLength = 0, thislen; 480 u16 chain, EUN; 481 482 for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) { 483 EUN = nftl->EUNtable[chain]; 484 thislen = 0; 485 486 while (EUN <= nftl->lastEUN) { 487 thislen++; 488 //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN); 489 EUN = nftl->ReplUnitTable[EUN] & 0x7fff; 490 if (thislen > 0xff00) { 491 printk("Endless loop in Virtual Chain %d: Unit %x\n", 492 chain, EUN); 493 } 494 if (thislen > 0xff10) { 495 /* Actually, don't return failure. Just ignore this chain and 496 get on with it. */ 497 thislen = 0; 498 break; 499 } 500 } 501 502 if (thislen > ChainLength) { 503 //printk("New longest chain is %d with length %d\n", chain, thislen); 504 ChainLength = thislen; 505 LongestChain = chain; 506 } 507 } 508 509 if (ChainLength < 2) { 510 printk(KERN_WARNING "No Virtual Unit Chains available for folding. " 511 "Failing request\n"); 512 return BLOCK_NIL; 513 } 514 515 return NFTL_foldchain (nftl, LongestChain, pendingblock); 516 } 517 518 /* NFTL_findwriteunit: Return the unit number into which we can write 519 for this block. Make it available if it isn't already 520 */ 521 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) 522 { 523 u16 lastEUN; 524 u16 thisVUC = block / (nftl->EraseSize / 512); 525 struct mtd_info *mtd = nftl->mbd.mtd; 526 unsigned int writeEUN; 527 unsigned long blockofs = (block * 512) & (nftl->EraseSize -1); 528 size_t retlen; 529 int silly, silly2 = 3; 530 struct nftl_oob oob; 531 532 do { 533 /* Scan the media to find a unit in the VUC which has 534 a free space for the block in question. 535 */ 536 537 /* This condition catches the 0x[7f]fff cases, as well as 538 being a sanity check for past-end-of-media access 539 */ 540 lastEUN = BLOCK_NIL; 541 writeEUN = nftl->EUNtable[thisVUC]; 542 silly = MAX_LOOPS; 543 while (writeEUN <= nftl->lastEUN) { 544 struct nftl_bci bci; 545 size_t retlen; 546 unsigned int status; 547 548 lastEUN = writeEUN; 549 550 nftl_read_oob(mtd, 551 (writeEUN * nftl->EraseSize) + blockofs, 552 8, &retlen, (char *)&bci); 553 554 pr_debug("Status of block %d in EUN %d is %x\n", 555 block , writeEUN, le16_to_cpu(bci.Status)); 556 557 status = bci.Status | bci.Status1; 558 switch(status) { 559 case SECTOR_FREE: 560 return writeEUN; 561 562 case SECTOR_DELETED: 563 case SECTOR_USED: 564 case SECTOR_IGNORE: 565 break; 566 default: 567 // Invalid block. Don't use it any more. Must implement. 568 break; 569 } 570 571 if (!silly--) { 572 printk(KERN_WARNING 573 "Infinite loop in Virtual Unit Chain 0x%x\n", 574 thisVUC); 575 return BLOCK_NIL; 576 } 577 578 /* Skip to next block in chain */ 579 writeEUN = nftl->ReplUnitTable[writeEUN]; 580 } 581 582 /* OK. We didn't find one in the existing chain, or there 583 is no existing chain. */ 584 585 /* Try to find an already-free block */ 586 writeEUN = NFTL_findfreeblock(nftl, 0); 587 588 if (writeEUN == BLOCK_NIL) { 589 /* That didn't work - there were no free blocks just 590 waiting to be picked up. We're going to have to fold 591 a chain to make room. 592 */ 593 594 /* First remember the start of this chain */ 595 //u16 startEUN = nftl->EUNtable[thisVUC]; 596 597 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); 598 writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL); 599 600 if (writeEUN == BLOCK_NIL) { 601 /* OK, we accept that the above comment is 602 lying - there may have been free blocks 603 last time we called NFTL_findfreeblock(), 604 but they are reserved for when we're 605 desperate. Well, now we're desperate. 606 */ 607 pr_debug("Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); 608 writeEUN = NFTL_findfreeblock(nftl, 1); 609 } 610 if (writeEUN == BLOCK_NIL) { 611 /* Ouch. This should never happen - we should 612 always be able to make some room somehow. 613 If we get here, we've allocated more storage 614 space than actual media, or our makefreeblock 615 routine is missing something. 616 */ 617 printk(KERN_WARNING "Cannot make free space.\n"); 618 return BLOCK_NIL; 619 } 620 //printk("Restarting scan\n"); 621 continue; 622 } 623 624 /* We've found a free block. Insert it into the chain. */ 625 626 if (lastEUN != BLOCK_NIL) { 627 thisVUC |= 0x8000; /* It's a replacement block */ 628 } else { 629 /* The first block in a new chain */ 630 nftl->EUNtable[thisVUC] = writeEUN; 631 } 632 633 /* set up the actual EUN we're writing into */ 634 /* Both in our cache... */ 635 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL; 636 637 /* ... and on the flash itself */ 638 nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8, 639 &retlen, (char *)&oob.u); 640 641 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); 642 643 nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8, 644 &retlen, (char *)&oob.u); 645 646 /* we link the new block to the chain only after the 647 block is ready. It avoids the case where the chain 648 could point to a free block */ 649 if (lastEUN != BLOCK_NIL) { 650 /* Both in our cache... */ 651 nftl->ReplUnitTable[lastEUN] = writeEUN; 652 /* ... and on the flash itself */ 653 nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8, 654 8, &retlen, (char *)&oob.u); 655 656 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum 657 = cpu_to_le16(writeEUN); 658 659 nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8, 660 8, &retlen, (char *)&oob.u); 661 } 662 663 return writeEUN; 664 665 } while (silly2--); 666 667 printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n", 668 thisVUC); 669 return BLOCK_NIL; 670 } 671 672 static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, 673 char *buffer) 674 { 675 struct NFTLrecord *nftl = (void *)mbd; 676 u16 writeEUN; 677 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); 678 size_t retlen; 679 struct nftl_oob oob; 680 681 writeEUN = NFTL_findwriteunit(nftl, block); 682 683 if (writeEUN == BLOCK_NIL) { 684 printk(KERN_WARNING 685 "NFTL_writeblock(): Cannot find block to write to\n"); 686 /* If we _still_ haven't got a block to use, we're screwed */ 687 return 1; 688 } 689 690 memset(&oob, 0xff, sizeof(struct nftl_oob)); 691 oob.b.Status = oob.b.Status1 = SECTOR_USED; 692 693 nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, 694 512, &retlen, (char *)buffer, (char *)&oob); 695 return 0; 696 } 697 #endif /* CONFIG_NFTL_RW */ 698 699 static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, 700 char *buffer) 701 { 702 struct NFTLrecord *nftl = (void *)mbd; 703 struct mtd_info *mtd = nftl->mbd.mtd; 704 u16 lastgoodEUN; 705 u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)]; 706 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); 707 unsigned int status; 708 int silly = MAX_LOOPS; 709 size_t retlen; 710 struct nftl_bci bci; 711 712 lastgoodEUN = BLOCK_NIL; 713 714 if (thisEUN != BLOCK_NIL) { 715 while (thisEUN < nftl->nb_blocks) { 716 if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) + 717 blockofs, 8, &retlen, 718 (char *)&bci) < 0) 719 status = SECTOR_IGNORE; 720 else 721 status = bci.Status | bci.Status1; 722 723 switch (status) { 724 case SECTOR_FREE: 725 /* no modification of a sector should follow a free sector */ 726 goto the_end; 727 case SECTOR_DELETED: 728 lastgoodEUN = BLOCK_NIL; 729 break; 730 case SECTOR_USED: 731 lastgoodEUN = thisEUN; 732 break; 733 case SECTOR_IGNORE: 734 break; 735 default: 736 printk("Unknown status for block %ld in EUN %d: %x\n", 737 block, thisEUN, status); 738 break; 739 } 740 741 if (!silly--) { 742 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n", 743 block / (nftl->EraseSize / 512)); 744 return 1; 745 } 746 thisEUN = nftl->ReplUnitTable[thisEUN]; 747 } 748 } 749 750 the_end: 751 if (lastgoodEUN == BLOCK_NIL) { 752 /* the requested block is not on the media, return all 0x00 */ 753 memset(buffer, 0, 512); 754 } else { 755 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs; 756 size_t retlen; 757 int res = mtd_read(mtd, ptr, 512, &retlen, buffer); 758 759 if (res < 0 && !mtd_is_bitflip(res)) 760 return -EIO; 761 } 762 return 0; 763 } 764 765 static int nftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) 766 { 767 struct NFTLrecord *nftl = (void *)dev; 768 769 geo->heads = nftl->heads; 770 geo->sectors = nftl->sectors; 771 geo->cylinders = nftl->cylinders; 772 773 return 0; 774 } 775 776 /**************************************************************************** 777 * 778 * Module stuff 779 * 780 ****************************************************************************/ 781 782 783 static struct mtd_blktrans_ops nftl_tr = { 784 .name = "nftl", 785 .major = NFTL_MAJOR, 786 .part_bits = NFTL_PARTN_BITS, 787 .blksize = 512, 788 .getgeo = nftl_getgeo, 789 .readsect = nftl_readblock, 790 #ifdef CONFIG_NFTL_RW 791 .writesect = nftl_writeblock, 792 #endif 793 .add_mtd = nftl_add_mtd, 794 .remove_dev = nftl_remove_dev, 795 .owner = THIS_MODULE, 796 }; 797 798 module_mtd_blktrans(nftl_tr); 799 800 MODULE_LICENSE("GPL"); 801 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al."); 802 MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium"); 803 MODULE_ALIAS_BLOCKDEV_MAJOR(NFTL_MAJOR); 804