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