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