[go: nahoru, domu]

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