• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/mtd/
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
48static 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
131static 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 */
145int 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 */
166int 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 */
189static 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 */
212static 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
253static 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
488static 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*/
540static 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
692static 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
719static 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
785static 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
803static 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
818static int __init init_nftl(void)
819{
820	return register_mtd_blktrans(&nftl_tr);
821}
822
823static void __exit cleanup_nftl(void)
824{
825	deregister_mtd_blktrans(&nftl_tr);
826}
827
828module_init(init_nftl);
829module_exit(cleanup_nftl);
830
831MODULE_LICENSE("GPL");
832MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
833MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");
834MODULE_ALIAS_BLOCKDEV_MAJOR(NFTL_MAJOR);
835