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