xref: /linux/drivers/mtd/nftlcore.c (revision b4ada0618eed0fbd1b1630f73deb048c592b06a1)
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