aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nftlcore.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 13:24:08 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 13:24:08 -0500
commitb3ce1debe2685383a9ad6ace9c49869c3968c013 (patch)
treedcb606fac467d6ce78a9c608a1e0d2323af44f2b /drivers/mtd/nftlcore.c
parent5b2f7ffcb734d3046144dfbd5ac6d76254a9e522 (diff)
parentc2965f1129ee54afcc4ef293ff0f25fa3a7e7392 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6
Some manual fixups for clashing kfree() cleanups etc.
Diffstat (limited to 'drivers/mtd/nftlcore.c')
-rw-r--r--drivers/mtd/nftlcore.c80
1 files changed, 40 insertions, 40 deletions
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 062ff3877536..d7cd5fa16ba4 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -1,7 +1,7 @@
1/* Linux driver for NAND Flash Translation Layer */ 1/* Linux driver for NAND Flash Translation Layer */
2/* (c) 1999 Machine Vision Holdings, Inc. */ 2/* (c) 1999 Machine Vision Holdings, Inc. */
3/* Author: David Woodhouse <dwmw2@infradead.org> */ 3/* Author: David Woodhouse <dwmw2@infradead.org> */
4/* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */ 4/* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */
5 5
6/* 6/*
7 The contents of this file are distributed under the GNU General 7 The contents of this file are distributed under the GNU General
@@ -101,14 +101,14 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
101 101
102 if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { 102 if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
103 /* 103 /*
104 Oh no we don't have 104 Oh no we don't have
105 mbd.size == heads * cylinders * sectors 105 mbd.size == heads * cylinders * sectors
106 */ 106 */
107 printk(KERN_WARNING "NFTL: cannot calculate a geometry to " 107 printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
108 "match size of 0x%lx.\n", nftl->mbd.size); 108 "match size of 0x%lx.\n", nftl->mbd.size);
109 printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " 109 printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
110 "(== 0x%lx sects)\n", 110 "(== 0x%lx sects)\n",
111 nftl->cylinders, nftl->heads , nftl->sectors, 111 nftl->cylinders, nftl->heads , nftl->sectors,
112 (long)nftl->cylinders * (long)nftl->heads * 112 (long)nftl->cylinders * (long)nftl->heads *
113 (long)nftl->sectors ); 113 (long)nftl->sectors );
114 } 114 }
@@ -174,7 +174,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
174 174
175 if (!silly--) { 175 if (!silly--) {
176 printk("Argh! No free blocks found! LastFreeEUN = %d, " 176 printk("Argh! No free blocks found! LastFreeEUN = %d, "
177 "FirstEUN = %d\n", nftl->LastFreeEUN, 177 "FirstEUN = %d\n", nftl->LastFreeEUN,
178 le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); 178 le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
179 return 0xffff; 179 return 0xffff;
180 } 180 }
@@ -206,7 +206,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
206 "Virtual Unit Chain %d!\n", thisVUC); 206 "Virtual Unit Chain %d!\n", thisVUC);
207 return BLOCK_NIL; 207 return BLOCK_NIL;
208 } 208 }
209 209
210 /* Scan to find the Erase Unit which holds the actual data for each 210 /* Scan to find the Erase Unit which holds the actual data for each
211 512-byte block within the Chain. 211 512-byte block within the Chain.
212 */ 212 */
@@ -223,7 +223,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
223 if (block == 2) { 223 if (block == 2) {
224 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; 224 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
225 if (foldmark == FOLD_MARK_IN_PROGRESS) { 225 if (foldmark == FOLD_MARK_IN_PROGRESS) {
226 DEBUG(MTD_DEBUG_LEVEL1, 226 DEBUG(MTD_DEBUG_LEVEL1,
227 "Write Inhibited on EUN %d\n", thisEUN); 227 "Write Inhibited on EUN %d\n", thisEUN);
228 inplace = 0; 228 inplace = 0;
229 } else { 229 } else {
@@ -245,7 +245,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
245 if (!BlockFreeFound[block]) 245 if (!BlockFreeFound[block])
246 BlockMap[block] = thisEUN; 246 BlockMap[block] = thisEUN;
247 else 247 else
248 printk(KERN_WARNING 248 printk(KERN_WARNING
249 "SECTOR_USED found after SECTOR_FREE " 249 "SECTOR_USED found after SECTOR_FREE "
250 "in Virtual Unit Chain %d for block %d\n", 250 "in Virtual Unit Chain %d for block %d\n",
251 thisVUC, block); 251 thisVUC, block);
@@ -254,7 +254,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
254 if (!BlockFreeFound[block]) 254 if (!BlockFreeFound[block])
255 BlockMap[block] = BLOCK_NIL; 255 BlockMap[block] = BLOCK_NIL;
256 else 256 else
257 printk(KERN_WARNING 257 printk(KERN_WARNING
258 "SECTOR_DELETED found after SECTOR_FREE " 258 "SECTOR_DELETED found after SECTOR_FREE "
259 "in Virtual Unit Chain %d for block %d\n", 259 "in Virtual Unit Chain %d for block %d\n",
260 thisVUC, block); 260 thisVUC, block);
@@ -273,14 +273,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
273 thisVUC); 273 thisVUC);
274 return BLOCK_NIL; 274 return BLOCK_NIL;
275 } 275 }
276 276
277 thisEUN = nftl->ReplUnitTable[thisEUN]; 277 thisEUN = nftl->ReplUnitTable[thisEUN];
278 } 278 }
279 279
280 if (inplace) { 280 if (inplace) {
281 /* We're being asked to be a fold-in-place. Check 281 /* We're being asked to be a fold-in-place. Check
282 that all blocks which actually have data associated 282 that all blocks which actually have data associated
283 with them (i.e. BlockMap[block] != BLOCK_NIL) are 283 with them (i.e. BlockMap[block] != BLOCK_NIL) are
284 either already present or SECTOR_FREE in the target 284 either already present or SECTOR_FREE in the target
285 block. If not, we're going to have to fold out-of-place 285 block. If not, we're going to have to fold out-of-place
286 anyway. 286 anyway.
@@ -293,7 +293,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
293 "block %d was %x lastEUN, " 293 "block %d was %x lastEUN, "
294 "and is in EUN %d (%s) %d\n", 294 "and is in EUN %d (%s) %d\n",
295 thisVUC, block, BlockLastState[block], 295 thisVUC, block, BlockLastState[block],
296 BlockMap[block], 296 BlockMap[block],
297 BlockMap[block]== targetEUN ? "==" : "!=", 297 BlockMap[block]== targetEUN ? "==" : "!=",
298 targetEUN); 298 targetEUN);
299 inplace = 0; 299 inplace = 0;
@@ -310,17 +310,17 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
310 inplace = 0; 310 inplace = 0;
311 } 311 }
312 } 312 }
313 313
314 if (!inplace) { 314 if (!inplace) {
315 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " 315 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
316 "Trying out-of-place\n", thisVUC); 316 "Trying out-of-place\n", thisVUC);
317 /* We need to find a targetEUN to fold into. */ 317 /* We need to find a targetEUN to fold into. */
318 targetEUN = NFTL_findfreeblock(nftl, 1); 318 targetEUN = NFTL_findfreeblock(nftl, 1);
319 if (targetEUN == BLOCK_NIL) { 319 if (targetEUN == BLOCK_NIL) {
320 /* Ouch. Now we're screwed. We need to do a 320 /* Ouch. Now we're screwed. We need to do a
321 fold-in-place of another chain to make room 321 fold-in-place of another chain to make room
322 for this one. We need a better way of selecting 322 for this one. We need a better way of selecting
323 which chain to fold, because makefreeblock will 323 which chain to fold, because makefreeblock will
324 only ask us to fold the same one again. 324 only ask us to fold the same one again.
325 */ 325 */
326 printk(KERN_WARNING 326 printk(KERN_WARNING
@@ -334,7 +334,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
334 chain by selecting the longer one */ 334 chain by selecting the longer one */
335 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); 335 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
336 oob.u.c.unused = 0xffffffff; 336 oob.u.c.unused = 0xffffffff;
337 MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 337 MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
338 8, &retlen, (char *)&oob.u); 338 8, &retlen, (char *)&oob.u);
339 } 339 }
340 340
@@ -357,14 +357,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
357 happen in case of media errors or deleted blocks) */ 357 happen in case of media errors or deleted blocks) */
358 if (BlockMap[block] == BLOCK_NIL) 358 if (BlockMap[block] == BLOCK_NIL)
359 continue; 359 continue;
360 360
361 ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 361 ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
362 512, &retlen, movebuf); 362 512, &retlen, movebuf);
363 if (ret < 0) { 363 if (ret < 0) {
364 ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) 364 ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
365 + (block * 512), 512, &retlen, 365 + (block * 512), 512, &retlen,
366 movebuf); 366 movebuf);
367 if (ret != -EIO) 367 if (ret != -EIO)
368 printk("Error went away on retry.\n"); 368 printk("Error went away on retry.\n");
369 } 369 }
370 memset(&oob, 0xff, sizeof(struct nftl_oob)); 370 memset(&oob, 0xff, sizeof(struct nftl_oob));
@@ -372,18 +372,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
372 MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), 372 MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
373 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); 373 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
374 } 374 }
375 375
376 /* add the header so that it is now a valid chain */ 376 /* add the header so that it is now a valid chain */
377 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum 377 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
378 = cpu_to_le16(thisVUC); 378 = cpu_to_le16(thisVUC);
379 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; 379 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
380 380
381 MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, 381 MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
382 8, &retlen, (char *)&oob.u); 382 8, &retlen, (char *)&oob.u);
383 383
384 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ 384 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
385 385
386 /* At this point, we have two different chains for this Virtual Unit, and no way to tell 386 /* At this point, we have two different chains for this Virtual Unit, and no way to tell
387 them apart. If we crash now, we get confused. However, both contain the same data, so we 387 them apart. If we crash now, we get confused. However, both contain the same data, so we
388 shouldn't actually lose data in this case. It's just that when we load up on a medium which 388 shouldn't actually lose data in this case. It's just that when we load up on a medium which
389 has duplicate chains, we need to free one of the chains because it's not necessary any more. 389 has duplicate chains, we need to free one of the chains because it's not necessary any more.
@@ -391,7 +391,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
391 thisEUN = nftl->EUNtable[thisVUC]; 391 thisEUN = nftl->EUNtable[thisVUC];
392 DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); 392 DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
393 393
394 /* For each block in the old chain (except the targetEUN of course), 394 /* For each block in the old chain (except the targetEUN of course),
395 free it and make it available for future use */ 395 free it and make it available for future use */
396 while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) { 396 while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
397 unsigned int EUNtmp; 397 unsigned int EUNtmp;
@@ -409,7 +409,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
409 } 409 }
410 thisEUN = EUNtmp; 410 thisEUN = EUNtmp;
411 } 411 }
412 412
413 /* Make this the new start of chain for thisVUC */ 413 /* Make this the new start of chain for thisVUC */
414 nftl->ReplUnitTable[targetEUN] = BLOCK_NIL; 414 nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
415 nftl->EUNtable[thisVUC] = targetEUN; 415 nftl->EUNtable[thisVUC] = targetEUN;
@@ -419,7 +419,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
419 419
420static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) 420static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
421{ 421{
422 /* This is the part that needs some cleverness applied. 422 /* This is the part that needs some cleverness applied.
423 For now, I'm doing the minimum applicable to actually 423 For now, I'm doing the minimum applicable to actually
424 get the thing to work. 424 get the thing to work.
425 Wear-levelling and other clever stuff needs to be implemented 425 Wear-levelling and other clever stuff needs to be implemented
@@ -466,7 +466,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
466 return NFTL_foldchain (nftl, LongestChain, pendingblock); 466 return NFTL_foldchain (nftl, LongestChain, pendingblock);
467} 467}
468 468
469/* NFTL_findwriteunit: Return the unit number into which we can write 469/* NFTL_findwriteunit: Return the unit number into which we can write
470 for this block. Make it available if it isn't already 470 for this block. Make it available if it isn't already
471*/ 471*/
472static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) 472static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
@@ -484,7 +484,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
484 a free space for the block in question. 484 a free space for the block in question.
485 */ 485 */
486 486
487 /* This condition catches the 0x[7f]fff cases, as well as 487 /* This condition catches the 0x[7f]fff cases, as well as
488 being a sanity check for past-end-of-media access 488 being a sanity check for past-end-of-media access
489 */ 489 */
490 lastEUN = BLOCK_NIL; 490 lastEUN = BLOCK_NIL;
@@ -499,7 +499,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
499 499
500 MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, 500 MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
501 8, &retlen, (char *)&bci); 501 8, &retlen, (char *)&bci);
502 502
503 DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", 503 DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
504 block , writeEUN, le16_to_cpu(bci.Status)); 504 block , writeEUN, le16_to_cpu(bci.Status));
505 505
@@ -514,10 +514,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
514 break; 514 break;
515 default: 515 default:
516 // Invalid block. Don't use it any more. Must implement. 516 // Invalid block. Don't use it any more. Must implement.
517 break; 517 break;
518 } 518 }
519 519
520 if (!silly--) { 520 if (!silly--) {
521 printk(KERN_WARNING 521 printk(KERN_WARNING
522 "Infinite loop in Virtual Unit Chain 0x%x\n", 522 "Infinite loop in Virtual Unit Chain 0x%x\n",
523 thisVUC); 523 thisVUC);
@@ -528,7 +528,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
528 writeEUN = nftl->ReplUnitTable[writeEUN]; 528 writeEUN = nftl->ReplUnitTable[writeEUN];
529 } 529 }
530 530
531 /* OK. We didn't find one in the existing chain, or there 531 /* OK. We didn't find one in the existing chain, or there
532 is no existing chain. */ 532 is no existing chain. */
533 533
534 /* Try to find an already-free block */ 534 /* Try to find an already-free block */
@@ -542,12 +542,12 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
542 542
543 /* First remember the start of this chain */ 543 /* First remember the start of this chain */
544 //u16 startEUN = nftl->EUNtable[thisVUC]; 544 //u16 startEUN = nftl->EUNtable[thisVUC];
545 545
546 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); 546 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
547 writeEUN = NFTL_makefreeblock(nftl, 0xffff); 547 writeEUN = NFTL_makefreeblock(nftl, 0xffff);
548 548
549 if (writeEUN == BLOCK_NIL) { 549 if (writeEUN == BLOCK_NIL) {
550 /* OK, we accept that the above comment is 550 /* OK, we accept that the above comment is
551 lying - there may have been free blocks 551 lying - there may have been free blocks
552 last time we called NFTL_findfreeblock(), 552 last time we called NFTL_findfreeblock(),
553 but they are reserved for when we're 553 but they are reserved for when we're
@@ -558,21 +558,21 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
558 } 558 }
559 if (writeEUN == BLOCK_NIL) { 559 if (writeEUN == BLOCK_NIL) {
560 /* Ouch. This should never happen - we should 560 /* Ouch. This should never happen - we should
561 always be able to make some room somehow. 561 always be able to make some room somehow.
562 If we get here, we've allocated more storage 562 If we get here, we've allocated more storage
563 space than actual media, or our makefreeblock 563 space than actual media, or our makefreeblock
564 routine is missing something. 564 routine is missing something.
565 */ 565 */
566 printk(KERN_WARNING "Cannot make free space.\n"); 566 printk(KERN_WARNING "Cannot make free space.\n");
567 return BLOCK_NIL; 567 return BLOCK_NIL;
568 } 568 }
569 //printk("Restarting scan\n"); 569 //printk("Restarting scan\n");
570 lastEUN = BLOCK_NIL; 570 lastEUN = BLOCK_NIL;
571 continue; 571 continue;
572 } 572 }
573 573
574 /* We've found a free block. Insert it into the chain. */ 574 /* We've found a free block. Insert it into the chain. */
575 575
576 if (lastEUN != BLOCK_NIL) { 576 if (lastEUN != BLOCK_NIL) {
577 thisVUC |= 0x8000; /* It's a replacement block */ 577 thisVUC |= 0x8000; /* It's a replacement block */
578 } else { 578 } else {
@@ -745,7 +745,7 @@ extern char nftlmountrev[];
745 745
746static int __init init_nftl(void) 746static int __init init_nftl(void)
747{ 747{
748 printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev); 748 printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev);
749 749
750 return register_mtd_blktrans(&nftl_tr); 750 return register_mtd_blktrans(&nftl_tr);
751} 751}