Hopefully get the Kconfig PCI stuff right, finally.
[linux-2.6/linux-mips.git] / drivers / mtd / nftlcore.c
blob6b5ab7bd56db1aff7c2c2afd0c654cac0dbbd17f
1 /* Linux driver for NAND Flash Translation Layer */
2 /* (c) 1999 Machine Vision Holdings, Inc. */
3 /* Author: David Woodhouse <dwmw2@infradead.org> */
4 /* $Id: nftlcore.c,v 1.82 2001/10/02 15:05:11 dwmw2 Exp $ */
6 /*
7 The contents of this file are distributed under the GNU General
8 Public License version 2. The author places no additional
9 restrictions of any kind on it.
12 #define PRERELEASE
14 #include <linux/config.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <asm/errno.h>
18 #include <asm/io.h>
19 #include <asm/uaccess.h>
20 #include <linux/miscdevice.h>
21 #include <linux/pci.h>
22 #include <linux/delay.h>
23 #include <linux/slab.h>
24 #include <linux/sched.h>
25 #include <linux/init.h>
26 #include <linux/blkpg.h>
27 #include <linux/buffer_head.h>
29 #ifdef CONFIG_KMOD
30 #include <linux/kmod.h>
31 #endif
32 #include <linux/mtd/mtd.h>
33 #include <linux/mtd/nftl.h>
34 #include <linux/mtd/compatmac.h>
36 /* maximum number of loops while examining next block, to have a
37 chance to detect consistency problems (they should never happen
38 because of the checks done in the mounting */
40 #define MAX_LOOPS 10000
42 /* NFTL block device stuff */
43 #define MAJOR_NR NFTL_MAJOR
45 #include <linux/blk.h>
46 #include <linux/hdreg.h>
48 /* Linux-specific block device functions */
50 struct NFTLrecord *NFTLs[MAX_NFTLS];
52 static struct request_queue nftl_queue;
54 static void NFTL_setup(struct mtd_info *mtd)
56 int i;
57 struct NFTLrecord *nftl;
58 unsigned long temp;
59 int firstfree = -1;
60 struct gendisk *gd;
62 DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
64 for (i = 0; i < MAX_NFTLS; i++) {
65 if (!NFTLs[i] && firstfree == -1)
66 firstfree = i;
67 else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
68 /* This is a Spare Media Header for an NFTL we've already found */
69 DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
70 return;
73 if (firstfree == -1) {
74 printk(KERN_WARNING "No more NFTL slot available\n");
75 return;
78 nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
79 gd = alloc_disk(1 << NFTL_PARTN_BITS);
80 if (!nftl || !gd) {
81 kfree(nftl);
82 put_disk(gd);
83 printk(KERN_WARNING "Out of memory for NFTL data structures\n");
84 return;
87 init_MUTEX(&nftl->mutex);
89 /* get physical parameters */
90 nftl->EraseSize = mtd->erasesize;
91 nftl->nb_blocks = mtd->size / mtd->erasesize;
92 nftl->mtd = mtd;
94 if (NFTL_mount(nftl) < 0) {
95 printk(KERN_WARNING "Could not mount NFTL device\n");
96 kfree(nftl);
97 put_disk(gd);
98 return;
101 /* OK, it's a new one. Set up all the data structures. */
102 #ifdef PSYCHO_DEBUG
103 printk("Found new NFTL nftl%c\n", firstfree + 'a');
104 #endif
106 /* linux stuff */
107 nftl->cylinders = 1024;
108 nftl->heads = 16;
110 temp = nftl->cylinders * nftl->heads;
111 nftl->sectors = nftl->nr_sects / temp;
112 if (nftl->nr_sects % temp) {
113 nftl->sectors++;
114 temp = nftl->cylinders * nftl->sectors;
115 nftl->heads = nftl->nr_sects / temp;
117 if (nftl->nr_sects % temp) {
118 nftl->heads++;
119 temp = nftl->heads * nftl->sectors;
120 nftl->cylinders = nftl->nr_sects / temp;
124 if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
125 printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
126 "match size of 0x%lx.\n", nftl->nr_sects);
127 printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n",
128 nftl->cylinders, nftl->heads , nftl->sectors,
129 (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
131 /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
133 NFTLs[firstfree] = nftl;
134 sprintf(gd->disk_name, "nftl%c", 'a' + firstfree);
135 gd->major = MAJOR_NR;
136 gd->first_minor = firstfree << NFTL_PARTN_BITS;
137 set_capacity(gd, nftl->nr_sects);
138 nftl->disk = gd;
139 gd->private_data = nftl;
140 gd->queue = &nftl_queue;
141 add_disk(gd);
144 static void NFTL_unsetup(int i)
146 struct NFTLrecord *nftl = NFTLs[i];
148 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
150 NFTLs[i] = NULL;
152 if (nftl->ReplUnitTable)
153 kfree(nftl->ReplUnitTable);
154 if (nftl->EUNtable)
155 kfree(nftl->EUNtable);
156 del_gendisk(nftl->disk);
157 put_disk(nftl->disk);
158 kfree(nftl);
161 /* Search the MTD device for NFTL partitions */
162 static void NFTL_notify_add(struct mtd_info *mtd)
164 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
166 if (mtd) {
167 if (!mtd->read_oob) {
168 /* If this MTD doesn't have out-of-band data,
169 then there's no point continuing */
170 DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
171 return;
173 DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n",
174 mtd->read, mtd->size, mtd->erasesize);
176 NFTL_setup(mtd);
180 static void NFTL_notify_remove(struct mtd_info *mtd)
182 int i;
184 for (i = 0; i < MAX_NFTLS; i++) {
185 if (NFTLs[i] && NFTLs[i]->mtd == mtd)
186 NFTL_unsetup(i);
190 #ifdef CONFIG_NFTL_RW
192 /* Actual NFTL access routines */
193 /* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
194 * when the give Virtual Unit Chain
196 static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
198 /* For a given Virtual Unit Chain: find or create a free block and
199 add it to the chain */
200 /* We're passed the number of the last EUN in the chain, to save us from
201 having to look it up again */
202 u16 pot = nftl->LastFreeEUN;
203 int silly = nftl->nb_blocks;
205 /* Normally, we force a fold to happen before we run out of free blocks completely */
206 if (!desperate && nftl->numfreeEUNs < 2) {
207 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
208 return 0xffff;
211 /* Scan for a free block */
212 do {
213 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
214 nftl->LastFreeEUN = pot;
215 nftl->numfreeEUNs--;
216 return pot;
219 /* This will probably point to the MediaHdr unit itself,
220 right at the beginning of the partition. But that unit
221 (and the backup unit too) should have the UCI set
222 up so that it's not selected for overwriting */
223 if (++pot > nftl->lastEUN)
224 pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
226 if (!silly--) {
227 printk("Argh! No free blocks found! LastFreeEUN = %d, "
228 "FirstEUN = %d\n", nftl->LastFreeEUN,
229 le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
230 return 0xffff;
232 } while (pot != nftl->LastFreeEUN);
234 return 0xffff;
237 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
239 u16 BlockMap[MAX_SECTORS_PER_UNIT];
240 unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
241 unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
242 unsigned int thisEUN;
243 int block;
244 int silly;
245 unsigned int targetEUN;
246 struct nftl_oob oob;
247 int inplace = 1;
248 size_t retlen;
250 memset(BlockMap, 0xff, sizeof(BlockMap));
251 memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
253 thisEUN = nftl->EUNtable[thisVUC];
255 if (thisEUN == BLOCK_NIL) {
256 printk(KERN_WARNING "Trying to fold non-existent "
257 "Virtual Unit Chain %d!\n", thisVUC);
258 return BLOCK_NIL;
261 /* Scan to find the Erase Unit which holds the actual data for each
262 512-byte block within the Chain.
264 silly = MAX_LOOPS;
265 targetEUN = BLOCK_NIL;
266 while (thisEUN <= nftl->lastEUN ) {
267 unsigned int status, foldmark;
269 targetEUN = thisEUN;
270 for (block = 0; block < nftl->EraseSize / 512; block ++) {
271 MTD_READOOB(nftl->mtd,
272 (thisEUN * nftl->EraseSize) + (block * 512),
273 16 , &retlen, (char *)&oob);
274 if (block == 2) {
275 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
276 if (foldmark == FOLD_MARK_IN_PROGRESS) {
277 DEBUG(MTD_DEBUG_LEVEL1,
278 "Write Inhibited on EUN %d\n", thisEUN);
279 inplace = 0;
280 } else {
281 /* There's no other reason not to do inplace,
282 except ones that come later. So we don't need
283 to preserve inplace */
284 inplace = 1;
287 status = oob.b.Status | oob.b.Status1;
288 BlockLastState[block] = status;
290 switch(status) {
291 case SECTOR_FREE:
292 BlockFreeFound[block] = 1;
293 break;
295 case SECTOR_USED:
296 if (!BlockFreeFound[block])
297 BlockMap[block] = thisEUN;
298 else
299 printk(KERN_WARNING
300 "SECTOR_USED found after SECTOR_FREE "
301 "in Virtual Unit Chain %d for block %d\n",
302 thisVUC, block);
303 break;
304 case SECTOR_DELETED:
305 if (!BlockFreeFound[block])
306 BlockMap[block] = BLOCK_NIL;
307 else
308 printk(KERN_WARNING
309 "SECTOR_DELETED found after SECTOR_FREE "
310 "in Virtual Unit Chain %d for block %d\n",
311 thisVUC, block);
312 break;
314 case SECTOR_IGNORE:
315 break;
316 default:
317 printk("Unknown status for block %d in EUN %d: %x\n",
318 block, thisEUN, status);
322 if (!silly--) {
323 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
324 thisVUC);
325 return BLOCK_NIL;
328 thisEUN = nftl->ReplUnitTable[thisEUN];
331 if (inplace) {
332 /* We're being asked to be a fold-in-place. Check
333 that all blocks which actually have data associated
334 with them (i.e. BlockMap[block] != BLOCK_NIL) are
335 either already present or SECTOR_FREE in the target
336 block. If not, we're going to have to fold out-of-place
337 anyway.
339 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
340 if (BlockLastState[block] != SECTOR_FREE &&
341 BlockMap[block] != BLOCK_NIL &&
342 BlockMap[block] != targetEUN) {
343 DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
344 "block %d was %x lastEUN, "
345 "and is in EUN %d (%s) %d\n",
346 thisVUC, block, BlockLastState[block],
347 BlockMap[block],
348 BlockMap[block]== targetEUN ? "==" : "!=",
349 targetEUN);
350 inplace = 0;
351 break;
355 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
356 pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
357 BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
358 SECTOR_FREE) {
359 DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
360 "Folding out of place.\n", targetEUN);
361 inplace = 0;
365 if (!inplace) {
366 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
367 "Trying out-of-place\n", thisVUC);
368 /* We need to find a targetEUN to fold into. */
369 targetEUN = NFTL_findfreeblock(nftl, 1);
370 if (targetEUN == BLOCK_NIL) {
371 /* Ouch. Now we're screwed. We need to do a
372 fold-in-place of another chain to make room
373 for this one. We need a better way of selecting
374 which chain to fold, because makefreeblock will
375 only ask us to fold the same one again.
377 printk(KERN_WARNING
378 "NFTL_findfreeblock(desperate) returns 0xffff.\n");
379 return BLOCK_NIL;
381 } else {
382 /* We put a fold mark in the chain we are folding only if
383 we fold in place to help the mount check code. If we do
384 not fold in place, it is possible to find the valid
385 chain by selecting the longer one */
386 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
387 oob.u.c.unused = 0xffffffff;
388 MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
389 8, &retlen, (char *)&oob.u);
392 /* OK. We now know the location of every block in the Virtual Unit Chain,
393 and the Erase Unit into which we are supposed to be copying.
394 Go for it.
396 DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
397 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
398 unsigned char movebuf[512];
399 int ret;
401 /* If it's in the target EUN already, or if it's pending write, do nothing */
402 if (BlockMap[block] == targetEUN ||
403 (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
404 continue;
407 /* copy only in non free block (free blocks can only
408 happen in case of media errors or deleted blocks) */
409 if (BlockMap[block] == BLOCK_NIL)
410 continue;
412 ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
413 + (block * 512), 512, &retlen, movebuf, (char *)&oob);
414 if (ret < 0) {
415 ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
416 + (block * 512), 512, &retlen,
417 movebuf, (char *)&oob);
418 if (ret != -EIO)
419 printk("Error went away on retry.\n");
421 MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
422 512, &retlen, movebuf, (char *)&oob);
425 /* add the header so that it is now a valid chain */
426 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
427 = cpu_to_le16(thisVUC);
428 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
430 MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8,
431 8, &retlen, (char *)&oob.u);
433 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
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.
440 thisEUN = nftl->EUNtable[thisVUC];
441 DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
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;
448 EUNtmp = nftl->ReplUnitTable[thisEUN];
450 if (NFTL_formatblock(nftl, thisEUN) < 0) {
451 /* could not erase : mark block as reserved
452 * FixMe: Update Bad Unit Table on disk
454 nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
455 } else {
456 /* correctly erased : mark it as free */
457 nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
458 nftl->numfreeEUNs++;
460 thisEUN = EUNtmp;
463 /* Make this the new start of chain for thisVUC */
464 nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
465 nftl->EUNtable[thisVUC] = targetEUN;
467 return targetEUN;
470 u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
472 /* This is the part that needs some cleverness applied.
473 For now, I'm doing the minimum applicable to actually
474 get the thing to work.
475 Wear-levelling and other clever stuff needs to be implemented
476 and we also need to do some assessment of the results when
477 the system loses power half-way through the routine.
479 u16 LongestChain = 0;
480 u16 ChainLength = 0, thislen;
481 u16 chain, EUN;
483 for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
484 EUN = nftl->EUNtable[chain];
485 thislen = 0;
487 while (EUN <= nftl->lastEUN) {
488 thislen++;
489 //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
490 EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
491 if (thislen > 0xff00) {
492 printk("Endless loop in Virtual Chain %d: Unit %x\n",
493 chain, EUN);
495 if (thislen > 0xff10) {
496 /* Actually, don't return failure. Just ignore this chain and
497 get on with it. */
498 thislen = 0;
499 break;
503 if (thislen > ChainLength) {
504 //printk("New longest chain is %d with length %d\n", chain, thislen);
505 ChainLength = thislen;
506 LongestChain = chain;
510 if (ChainLength < 2) {
511 printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
512 "Failing request\n");
513 return 0xffff;
516 return NFTL_foldchain (nftl, LongestChain, pendingblock);
519 /* NFTL_findwriteunit: Return the unit number into which we can write
520 for this block. Make it available if it isn't already
522 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
524 u16 lastEUN;
525 u16 thisVUC = block / (nftl->EraseSize / 512);
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;
532 do {
533 /* Scan the media to find a unit in the VUC which has
534 a free space for the block in question.
537 /* This condition catches the 0x[7f]fff cases, as well as
538 being a sanity check for past-end-of-media access
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;
548 lastEUN = writeEUN;
550 MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
551 8, &retlen, (char *)&bci);
553 DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
554 block , writeEUN, le16_to_cpu(bci.Status));
556 status = bci.Status | bci.Status1;
557 switch(status) {
558 case SECTOR_FREE:
559 return writeEUN;
561 case SECTOR_DELETED:
562 case SECTOR_USED:
563 case SECTOR_IGNORE:
564 break;
565 default:
566 // Invalid block. Don't use it any more. Must implement.
567 break;
570 if (!silly--) {
571 printk(KERN_WARNING
572 "Infinite loop in Virtual Unit Chain 0x%x\n",
573 thisVUC);
574 return 0xffff;
577 /* Skip to next block in chain */
578 writeEUN = nftl->ReplUnitTable[writeEUN];
581 /* OK. We didn't find one in the existing chain, or there
582 is no existing chain. */
584 /* Try to find an already-free block */
585 writeEUN = NFTL_findfreeblock(nftl, 0);
587 if (writeEUN == BLOCK_NIL) {
588 /* That didn't work - there were no free blocks just
589 waiting to be picked up. We're going to have to fold
590 a chain to make room.
593 /* First remember the start of this chain */
594 //u16 startEUN = nftl->EUNtable[thisVUC];
596 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
597 writeEUN = NFTL_makefreeblock(nftl, 0xffff);
599 if (writeEUN == BLOCK_NIL) {
600 /* OK, we accept that the above comment is
601 lying - there may have been free blocks
602 last time we called NFTL_findfreeblock(),
603 but they are reserved for when we're
604 desperate. Well, now we're desperate.
606 DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
607 writeEUN = NFTL_findfreeblock(nftl, 1);
609 if (writeEUN == BLOCK_NIL) {
610 /* Ouch. This should never happen - we should
611 always be able to make some room somehow.
612 If we get here, we've allocated more storage
613 space than actual media, or our makefreeblock
614 routine is missing something.
616 printk(KERN_WARNING "Cannot make free space.\n");
617 return BLOCK_NIL;
619 //printk("Restarting scan\n");
620 lastEUN = BLOCK_NIL;
621 continue;
624 /* We've found a free block. Insert it into the chain. */
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;
633 /* set up the actual EUN we're writing into */
634 /* Both in our cache... */
635 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
637 /* ... and on the flash itself */
638 MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
639 &retlen, (char *)&oob.u);
641 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
643 MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
644 &retlen, (char *)&oob.u);
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 MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
654 8, &retlen, (char *)&oob.u);
656 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
657 = cpu_to_le16(writeEUN);
659 MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
660 8, &retlen, (char *)&oob.u);
663 return writeEUN;
665 } while (silly2--);
667 printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
668 thisVUC);
669 return 0xffff;
672 static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
674 u16 writeEUN;
675 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
676 size_t retlen;
677 u8 eccbuf[6];
679 writeEUN = NFTL_findwriteunit(nftl, block);
681 if (writeEUN == BLOCK_NIL) {
682 printk(KERN_WARNING
683 "NFTL_writeblock(): Cannot find block to write to\n");
684 /* If we _still_ haven't got a block to use, we're screwed */
685 return 1;
688 MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
689 512, &retlen, (char *)buffer, (char *)eccbuf);
690 /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
692 return 0;
694 #endif /* CONFIG_NFTL_RW */
696 static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
698 u16 lastgoodEUN;
699 u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
700 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
701 unsigned int status;
702 int silly = MAX_LOOPS;
703 size_t retlen;
704 struct nftl_bci bci;
706 lastgoodEUN = BLOCK_NIL;
708 if (thisEUN != BLOCK_NIL) {
709 while (thisEUN < nftl->nb_blocks) {
710 if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
711 8, &retlen, (char *)&bci) < 0)
712 status = SECTOR_IGNORE;
713 else
714 status = bci.Status | bci.Status1;
716 switch (status) {
717 case SECTOR_FREE:
718 /* no modification of a sector should follow a free sector */
719 goto the_end;
720 case SECTOR_DELETED:
721 lastgoodEUN = BLOCK_NIL;
722 break;
723 case SECTOR_USED:
724 lastgoodEUN = thisEUN;
725 break;
726 case SECTOR_IGNORE:
727 break;
728 default:
729 printk("Unknown status for block %d in EUN %d: %x\n",
730 block, thisEUN, status);
731 break;
734 if (!silly--) {
735 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
736 block / (nftl->EraseSize / 512));
737 return 1;
739 thisEUN = nftl->ReplUnitTable[thisEUN];
743 the_end:
744 if (lastgoodEUN == BLOCK_NIL) {
745 /* the requested block is not on the media, return all 0x00 */
746 memset(buffer, 0, 512);
747 } else {
748 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
749 size_t retlen;
750 u_char eccbuf[6];
751 if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf))
752 return -EIO;
754 return 0;
757 static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
759 struct NFTLrecord *nftl = inode->i_bdev->bd_disk->private_data;
760 switch (cmd) {
761 case HDIO_GETGEO: {
762 struct hd_geometry g;
764 g.heads = nftl->heads;
765 g.sectors = nftl->sectors;
766 g.cylinders = nftl->cylinders;
767 g.start = get_start_sect(inode->i_bdev);
768 return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
770 case BLKFLSBUF:
771 fsync_bdev(inode->i_bdev);
772 invalidate_bdev(inode->i_bdev, 0);
773 if (nftl->mtd->sync)
774 nftl->mtd->sync(nftl->mtd);
775 return 0;
776 default:
777 return -EINVAL;
781 void nftl_request(struct request_queue *q)
783 struct request *req;
785 while ((req = elv_next_request(q)) != NULL) {
786 unsigned block = req->sector;
787 unsigned nsect = req->current_nr_sectors;
788 char *buffer = req->buffer;
789 struct NFTLrecord *nftl = req->rq_disk->private_data;
790 int res = 1; /* succeed */
792 /* We can do this because the generic code knows not to
793 touch the request at the head of the queue */
794 spin_unlock_irq(q->queue_lock);
796 DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
797 DEBUG(MTD_DEBUG_LEVEL3,
798 "NFTL %s request, from sector 0x%04llx for %d sectors\n",
799 (req->cmd == READ) ? "Read " : "Write",
800 (unsigned long long)req->sector, req->current_nr_sectors);
802 DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
803 down(&nftl->mutex);
804 DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
806 if (block + nsect > get_capacity(nftl->disk)) {
807 /* access past the end of device */
808 printk("%s: bad access: block = %d, count = %d\n",
809 nftl->disk->disk_name, block, nsect);
810 up(&nftl->mutex);
811 res = 0; /* fail */
812 goto repeat;
815 if (req->cmd == READ) {
816 DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
817 "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
819 for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
820 /* Read a single sector to req->buffer + (512 * i) */
821 if (NFTL_readblock(nftl, block, buffer)) {
822 DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
823 up(&nftl->mutex);
824 res = 0;
825 goto repeat;
829 DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
830 up(&nftl->mutex);
831 goto repeat;
832 } else if (rq_data_dir(req) == WRITE) {
833 DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
834 "(req->nr_sectors == %lx)\n", nsect, block,
835 req->nr_sectors);
836 #ifdef CONFIG_NFTL_RW
837 for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
838 /* Read a single sector to req->buffer + (512 * i) */
839 if (NFTL_writeblock(nftl, block, buffer)) {
840 DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
841 up(&nftl->mutex);
842 res = 0;
843 goto repeat;
846 DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
847 #else
848 res = 0; /* Writes always fail */
849 #endif /* CONFIG_NFTL_RW */
850 up(&nftl->mutex);
851 goto repeat;
852 } else {
853 DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
854 up(&nftl->mutex);
855 res = 0;
856 goto repeat;
858 repeat:
859 DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
860 spin_lock_irq(q->queue_lock);
861 end_request(req, res);
865 static struct kobject *nftl_probe(dev_t dev, int *part, void *data)
867 request_module("docprobe");
868 return NULL;
871 static int nftl_open(struct inode *ip, struct file *fp)
873 struct NFTLrecord *thisNFTL = ip->i_bdev->bd_disk->private_data;
875 DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
876 if (!thisNFTL)
877 return -ENODEV;
879 #ifndef CONFIG_NFTL_RW
880 if (fp->f_mode & FMODE_WRITE)
881 return -EROFS;
882 #endif /* !CONFIG_NFTL_RW */
884 if (!get_mtd_device(thisNFTL->mtd, -1))
885 return /* -E'SBUGGEREDOFF */ -ENXIO;
887 return 0;
890 static int nftl_release(struct inode *inode, struct file *fp)
892 struct NFTLrecord *thisNFTL = inode->i_bdev->bd_disk->private_data;
894 DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
896 if (thisNFTL->mtd->sync)
897 thisNFTL->mtd->sync(thisNFTL->mtd);
899 put_mtd_device(thisNFTL->mtd);
901 return 0;
903 static struct block_device_operations nftl_fops =
905 .owner = THIS_MODULE,
906 .open = nftl_open,
907 .release = nftl_release,
908 .ioctl = nftl_ioctl
911 /****************************************************************************
913 * Module stuff
915 ****************************************************************************/
917 static struct mtd_notifier nftl_notifier = {
918 .add = NFTL_notify_add,
919 .remove = NFTL_notify_remove
922 extern char nftlmountrev[];
923 static spinlock_t nftl_lock = SPIN_LOCK_UNLOCKED;
925 int __init init_nftl(void)
928 #ifdef PRERELEASE
929 printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev);
930 #endif
932 if (register_blkdev(MAJOR_NR, "nftl"))
933 return -EBUSY;
935 blk_register_region(MKDEV(MAJOR_NR, 0), 256,
936 THIS_MODULE, nftl_probe, NULL, NULL);
938 blk_init_queue(&nftl_queue, &nftl_request, &nftl_lock);
940 register_mtd_user(&nftl_notifier);
942 return 0;
945 static void __exit cleanup_nftl(void)
947 unregister_mtd_user(&nftl_notifier);
948 blk_unregister_region(MKDEV(MAJOR_NR, 0), 256);
949 unregister_blkdev(MAJOR_NR, "nftl");
950 blk_cleanup_queue(&nftl_queue);
953 module_init(init_nftl);
954 module_exit(cleanup_nftl);
956 MODULE_LICENSE("GPL");
957 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
958 MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");