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.1.1.1 2005/04/11 02:50:25 jack Exp $ */
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.
14 #include <linux/config.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <asm/errno.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>
29 #include <linux/kmod.h>
31 #include <linux/mtd/mtd.h>
32 #include <linux/mtd/nand.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
44 #define DEVICE_REQUEST nftl_request
45 #define DEVICE_OFF(device)
48 #include <linux/blk.h>
49 #include <linux/hdreg.h>
51 /* Linux-specific block device functions */
53 /* I _HATE_ the Linux block device setup more than anything else I've ever
54 * encountered, except ...
57 static int nftl_sizes[256];
58 static int nftl_blocksizes[256];
60 /* .. for the Linux partition table handling. */
61 struct hd_struct part_table[256];
63 #if LINUX_VERSION_CODE < 0x20328
64 static void dummy_init (struct gendisk *crap)
68 static struct gendisk nftl_gendisk = {
71 minor_shift: NFTL_PARTN_BITS, /* Bits to shift to get real from partition */
72 max_p: (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */
73 #if LINUX_VERSION_CODE < 0x20328
74 max_nr: MAX_NFTLS, /* maximum number of real */
75 init: dummy_init, /* init function */
77 part: part_table, /* hd struct */
78 sizes: nftl_sizes, /* block sizes */
81 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
82 #define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
83 #define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
85 #define BLK_INC_USE_COUNT do {} while(0)
86 #define BLK_DEC_USE_COUNT do {} while(0)
89 struct NFTLrecord *NFTLs[MAX_NFTLS];
91 static void NFTL_setup(struct mtd_info *mtd)
94 struct NFTLrecord *nftl;
98 DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
100 for (i = 0; i < MAX_NFTLS; i++) {
101 if (!NFTLs[i] && firstfree == -1)
103 else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
104 /* This is a Spare Media Header for an NFTL we've already found */
105 DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
109 if (firstfree == -1) {
110 printk(KERN_WARNING "No more NFTL slot available\n");
114 nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
116 printk(KERN_WARNING "Out of memory for NFTL data structures\n");
120 init_MUTEX(&nftl->mutex);
124 if (NFTL_mount(nftl) < 0) {
125 printk(KERN_WARNING "Could not mount NFTL device\n");
130 /* OK, it's a new one. Set up all the data structures. */
132 printk("Found new NFTL nftl%c\n", firstfree + 'a');
137 nftl->cylinders = 1024;
140 temp = nftl->cylinders * nftl->heads;
141 nftl->sectors = nftl->nr_sects / temp;
142 if (nftl->nr_sects % temp) {
144 temp = nftl->cylinders * nftl->sectors;
145 nftl->heads = nftl->nr_sects / temp;
147 if (nftl->nr_sects % temp) {
149 temp = nftl->heads * nftl->sectors;
150 nftl->cylinders = nftl->nr_sects / temp;
154 if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
155 printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
156 "match size of 0x%x.\n", nftl->nr_sects);
157 printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n",
158 nftl->cylinders, nftl->heads , nftl->sectors,
159 (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
161 /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
163 NFTLs[firstfree] = nftl;
164 /* Finally, set up the block device sizes */
165 nftl_sizes[firstfree * 16] = nftl->nr_sects;
166 //nftl_blocksizes[firstfree*16] = 512;
167 part_table[firstfree * 16].nr_sects = nftl->nr_sects;
169 nftl_gendisk.nr_real++;
171 /* partition check ... */
172 #if LINUX_VERSION_CODE < 0x20328
173 resetup_one_dev(&nftl_gendisk, firstfree);
175 grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects);
179 static void NFTL_unsetup(int i)
181 struct NFTLrecord *nftl = NFTLs[i];
183 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
187 if (nftl->ReplUnitTable)
188 kfree(nftl->ReplUnitTable);
190 kfree(nftl->EUNtable);
192 nftl_gendisk.nr_real--;
196 /* Search the MTD device for NFTL partitions */
197 static void NFTL_notify_add(struct mtd_info *mtd)
199 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
202 if (!mtd->read_oob) {
203 /* If this MTD doesn't have out-of-band data,
204 then there's no point continuing */
205 DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
208 DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n",
209 mtd->read, mtd->size, mtd->erasesize);
215 static void NFTL_notify_remove(struct mtd_info *mtd)
219 for (i = 0; i < MAX_NFTLS; i++) {
220 if (NFTLs[i] && NFTLs[i]->mtd == mtd)
225 #ifdef CONFIG_NFTL_RW
227 /* Actual NFTL access routines */
228 /* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
229 * when the give Virtual Unit Chain
231 static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
233 /* For a given Virtual Unit Chain: find or create a free block and
234 add it to the chain */
235 /* We're passed the number of the last EUN in the chain, to save us from
236 having to look it up again */
237 u16 pot = nftl->LastFreeEUN;
238 int silly = nftl->nb_blocks;
240 /* Normally, we force a fold to happen before we run out of free blocks completely */
241 if (!desperate && nftl->numfreeEUNs < 2) {
242 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
246 /* Scan for a free block */
248 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
249 nftl->LastFreeEUN = pot;
254 /* This will probably point to the MediaHdr unit itself,
255 right at the beginning of the partition. But that unit
256 (and the backup unit too) should have the UCI set
257 up so that it's not selected for overwriting */
258 if (++pot > nftl->lastEUN)
259 pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
262 printk("Argh! No free blocks found! LastFreeEUN = %d, "
263 "FirstEUN = %d\n", nftl->LastFreeEUN,
264 le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
267 } while (pot != nftl->LastFreeEUN);
272 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
274 u16 BlockMap[MAX_SECTORS_PER_UNIT];
275 unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
276 unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
277 unsigned int thisEUN;
280 unsigned int targetEUN;
285 memset(BlockMap, 0xff, sizeof(BlockMap));
286 memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
288 thisEUN = nftl->EUNtable[thisVUC];
290 if (thisEUN == BLOCK_NIL) {
291 printk(KERN_WARNING "Trying to fold non-existent "
292 "Virtual Unit Chain %d!\n", thisVUC);
296 /* Scan to find the Erase Unit which holds the actual data for each
297 512-byte block within the Chain.
300 targetEUN = BLOCK_NIL;
301 while (thisEUN <= nftl->lastEUN ) {
302 unsigned int status, foldmark;
305 for (block = 0; block < nftl->EraseSize / 512; block ++) {
306 MTD_READOOB(nftl->mtd,
307 (thisEUN * nftl->EraseSize) + (block * 512),
308 16 , &retlen, (char *)&oob);
310 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
311 if (foldmark == FOLD_MARK_IN_PROGRESS) {
312 DEBUG(MTD_DEBUG_LEVEL1,
313 "Write Inhibited on EUN %d\n", thisEUN);
316 /* There's no other reason not to do inplace,
317 except ones that come later. So we don't need
318 to preserve inplace */
322 status = oob.b.Status | oob.b.Status1;
323 BlockLastState[block] = status;
327 BlockFreeFound[block] = 1;
331 if (!BlockFreeFound[block])
332 BlockMap[block] = thisEUN;
335 "SECTOR_USED found after SECTOR_FREE "
336 "in Virtual Unit Chain %d for block %d\n",
340 if (!BlockFreeFound[block])
341 BlockMap[block] = BLOCK_NIL;
344 "SECTOR_DELETED found after SECTOR_FREE "
345 "in Virtual Unit Chain %d for block %d\n",
352 printk("Unknown status for block %d in EUN %d: %x\n",
353 block, thisEUN, status);
358 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
363 thisEUN = nftl->ReplUnitTable[thisEUN];
367 /* We're being asked to be a fold-in-place. Check
368 that all blocks which actually have data associated
369 with them (i.e. BlockMap[block] != BLOCK_NIL) are
370 either already present or SECTOR_FREE in the target
371 block. If not, we're going to have to fold out-of-place
374 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
375 if (BlockLastState[block] != SECTOR_FREE &&
376 BlockMap[block] != BLOCK_NIL &&
377 BlockMap[block] != targetEUN) {
378 DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
379 "block %d was %x lastEUN, "
380 "and is in EUN %d (%s) %d\n",
381 thisVUC, block, BlockLastState[block],
383 BlockMap[block]== targetEUN ? "==" : "!=",
390 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
391 pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
392 BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
394 DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
395 "Folding out of place.\n", targetEUN);
401 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
402 "Trying out-of-place\n", thisVUC);
403 /* We need to find a targetEUN to fold into. */
404 targetEUN = NFTL_findfreeblock(nftl, 1);
405 if (targetEUN == BLOCK_NIL) {
406 /* Ouch. Now we're screwed. We need to do a
407 fold-in-place of another chain to make room
408 for this one. We need a better way of selecting
409 which chain to fold, because makefreeblock will
410 only ask us to fold the same one again.
413 "NFTL_findfreeblock(desperate) returns 0xffff.\n");
417 /* We put a fold mark in the chain we are folding only if
418 we fold in place to help the mount check code. If we do
419 not fold in place, it is possible to find the valid
420 chain by selecting the longer one */
421 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
422 oob.u.c.unused = 0xffffffff;
423 MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
424 8, &retlen, (char *)&oob.u);
427 /* OK. We now know the location of every block in the Virtual Unit Chain,
428 and the Erase Unit into which we are supposed to be copying.
431 DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
432 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
433 unsigned char movebuf[512];
436 /* If it's in the target EUN already, or if it's pending write, do nothing */
437 if (BlockMap[block] == targetEUN ||
438 (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
442 /* copy only in non free block (free blocks can only
443 happen in case of media errors or deleted blocks) */
444 if (BlockMap[block] == BLOCK_NIL)
447 ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
448 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
450 ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
451 + (block * 512), 512, &retlen,
452 movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
454 printk("Error went away on retry.\n");
456 MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
457 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
460 /* add the header so that it is now a valid chain */
461 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
462 = cpu_to_le16(thisVUC);
463 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
465 MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8,
466 8, &retlen, (char *)&oob.u);
468 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
470 /* At this point, we have two different chains for this Virtual Unit, and no way to tell
471 them apart. If we crash now, we get confused. However, both contain the same data, so we
472 shouldn't actually lose data in this case. It's just that when we load up on a medium which
473 has duplicate chains, we need to free one of the chains because it's not necessary any more.
475 thisEUN = nftl->EUNtable[thisVUC];
476 DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
478 /* For each block in the old chain (except the targetEUN of course),
479 free it and make it available for future use */
480 while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
483 EUNtmp = nftl->ReplUnitTable[thisEUN];
485 if (NFTL_formatblock(nftl, thisEUN) < 0) {
486 /* could not erase : mark block as reserved
487 * FixMe: Update Bad Unit Table on disk
489 nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
491 /* correctly erased : mark it as free */
492 nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
498 /* Make this the new start of chain for thisVUC */
499 nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
500 nftl->EUNtable[thisVUC] = targetEUN;
505 u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
507 /* This is the part that needs some cleverness applied.
508 For now, I'm doing the minimum applicable to actually
509 get the thing to work.
510 Wear-levelling and other clever stuff needs to be implemented
511 and we also need to do some assessment of the results when
512 the system loses power half-way through the routine.
514 u16 LongestChain = 0;
515 u16 ChainLength = 0, thislen;
518 for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
519 EUN = nftl->EUNtable[chain];
522 while (EUN <= nftl->lastEUN) {
524 //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
525 EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
526 if (thislen > 0xff00) {
527 printk("Endless loop in Virtual Chain %d: Unit %x\n",
530 if (thislen > 0xff10) {
531 /* Actually, don't return failure. Just ignore this chain and
538 if (thislen > ChainLength) {
539 //printk("New longest chain is %d with length %d\n", chain, thislen);
540 ChainLength = thislen;
541 LongestChain = chain;
545 if (ChainLength < 2) {
546 printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
547 "Failing request\n");
551 return NFTL_foldchain (nftl, LongestChain, pendingblock);
554 /* NFTL_findwriteunit: Return the unit number into which we can write
555 for this block. Make it available if it isn't already
557 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
560 u16 thisVUC = block / (nftl->EraseSize / 512);
561 unsigned int writeEUN;
562 unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
564 int silly, silly2 = 3;
568 /* Scan the media to find a unit in the VUC which has
569 a free space for the block in question.
572 /* This condition catches the 0x[7f]fff cases, as well as
573 being a sanity check for past-end-of-media access
576 writeEUN = nftl->EUNtable[thisVUC];
578 while (writeEUN <= nftl->lastEUN) {
585 MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
586 8, &retlen, (char *)&bci);
588 DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
589 block , writeEUN, le16_to_cpu(bci.Status));
591 status = bci.Status | bci.Status1;
601 // Invalid block. Don't use it any more. Must implement.
607 "Infinite loop in Virtual Unit Chain 0x%x\n",
612 /* Skip to next block in chain */
613 writeEUN = nftl->ReplUnitTable[writeEUN];
616 /* OK. We didn't find one in the existing chain, or there
617 is no existing chain. */
619 /* Try to find an already-free block */
620 writeEUN = NFTL_findfreeblock(nftl, 0);
622 if (writeEUN == BLOCK_NIL) {
623 /* That didn't work - there were no free blocks just
624 waiting to be picked up. We're going to have to fold
625 a chain to make room.
628 /* First remember the start of this chain */
629 //u16 startEUN = nftl->EUNtable[thisVUC];
631 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
632 writeEUN = NFTL_makefreeblock(nftl, 0xffff);
634 if (writeEUN == BLOCK_NIL) {
635 /* OK, we accept that the above comment is
636 lying - there may have been free blocks
637 last time we called NFTL_findfreeblock(),
638 but they are reserved for when we're
639 desperate. Well, now we're desperate.
641 DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
642 writeEUN = NFTL_findfreeblock(nftl, 1);
644 if (writeEUN == BLOCK_NIL) {
645 /* Ouch. This should never happen - we should
646 always be able to make some room somehow.
647 If we get here, we've allocated more storage
648 space than actual media, or our makefreeblock
649 routine is missing something.
651 printk(KERN_WARNING "Cannot make free space.\n");
654 //printk("Restarting scan\n");
659 /* We've found a free block. Insert it into the chain. */
661 if (lastEUN != BLOCK_NIL) {
662 thisVUC |= 0x8000; /* It's a replacement block */
664 /* The first block in a new chain */
665 nftl->EUNtable[thisVUC] = writeEUN;
668 /* set up the actual EUN we're writing into */
669 /* Both in our cache... */
670 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
672 /* ... and on the flash itself */
673 MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
674 &retlen, (char *)&oob.u);
676 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
678 MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
679 &retlen, (char *)&oob.u);
681 /* we link the new block to the chain only after the
682 block is ready. It avoids the case where the chain
683 could point to a free block */
684 if (lastEUN != BLOCK_NIL) {
685 /* Both in our cache... */
686 nftl->ReplUnitTable[lastEUN] = writeEUN;
687 /* ... and on the flash itself */
688 MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
689 8, &retlen, (char *)&oob.u);
691 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
692 = cpu_to_le16(writeEUN);
694 MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
695 8, &retlen, (char *)&oob.u);
702 printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
707 static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
710 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
714 writeEUN = NFTL_findwriteunit(nftl, block);
716 if (writeEUN == BLOCK_NIL) {
718 "NFTL_writeblock(): Cannot find block to write to\n");
719 /* If we _still_ haven't got a block to use, we're screwed */
723 MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
724 512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
725 /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
729 #endif /* CONFIG_NFTL_RW */
731 static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
734 u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
735 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
737 int silly = MAX_LOOPS;
741 lastgoodEUN = BLOCK_NIL;
743 if (thisEUN != BLOCK_NIL) {
744 while (thisEUN < nftl->nb_blocks) {
745 if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
746 8, &retlen, (char *)&bci) < 0)
747 status = SECTOR_IGNORE;
749 status = bci.Status | bci.Status1;
753 /* no modification of a sector should follow a free sector */
756 lastgoodEUN = BLOCK_NIL;
759 lastgoodEUN = thisEUN;
764 printk("Unknown status for block %d in EUN %d: %x\n",
765 block, thisEUN, status);
770 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
771 block / (nftl->EraseSize / 512));
774 thisEUN = nftl->ReplUnitTable[thisEUN];
779 if (lastgoodEUN == BLOCK_NIL) {
780 /* the requested block is not on the media, return all 0x00 */
781 memset(buffer, 0, 512);
783 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
786 if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
792 static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
794 struct NFTLrecord *nftl;
797 nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS];
799 if (!nftl) return -EINVAL;
803 struct hd_geometry g;
805 g.heads = nftl->heads;
806 g.sectors = nftl->sectors;
807 g.cylinders = nftl->cylinders;
808 g.start = part_table[MINOR(inode->i_rdev)].start_sect;
809 return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
811 case BLKGETSIZE: /* Return device size */
812 return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
813 (unsigned long *) arg);
817 return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
822 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
823 fsync_dev(inode->i_rdev);
824 invalidate_buffers(inode->i_rdev);
826 nftl->mtd->sync(nftl->mtd);
830 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
831 if (nftl->usecount > 1) return -EBUSY;
833 * We have to flush all buffers and invalidate caches,
834 * or we won't be able to re-use the partitions,
835 * if there was a change and we don't want to reboot
837 p = (1<<NFTL_PARTN_BITS) - 1;
839 kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p);
840 if (part_table[p].nr_sects > 0)
841 invalidate_device (devp, 1);
843 part_table[MINOR(inode->i_dev)+p].start_sect = 0;
844 part_table[MINOR(inode->i_dev)+p].nr_sects = 0;
847 #if LINUX_VERSION_CODE < 0x20328
848 resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS);
850 grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS,
851 1<<NFTL_PARTN_BITS, nftl->nr_sects);
855 #if (LINUX_VERSION_CODE < 0x20303)
856 RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */
861 return blk_ioctl(inode->i_rdev, cmd, arg);
869 void nftl_request(RQFUNC_ARG)
871 unsigned int dev, block, nsect;
872 struct NFTLrecord *nftl;
878 INIT_REQUEST; /* blk.h */
881 /* We can do this because the generic code knows not to
882 touch the request at the head of the queue */
883 spin_unlock_irq(&io_request_lock);
885 DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
886 DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
887 (req->cmd == READ) ? "Read " : "Write",
888 req->sector, req->current_nr_sectors);
890 dev = MINOR(req->rq_dev);
892 nsect = req->current_nr_sectors;
893 buffer = req->buffer;
894 res = 1; /* succeed */
896 if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) {
897 /* there is no such partition */
898 printk("nftl: bad minor number: device = %s\n",
899 kdevname(req->rq_dev));
904 nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)];
905 DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
907 DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
909 if (block + nsect > part_table[dev].nr_sects) {
910 /* access past the end of device */
911 printk("nftl%c%d: bad access: block = %d, count = %d\n",
912 (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
918 block += part_table[dev].start_sect;
920 if (req->cmd == READ) {
921 DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
922 "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
924 for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
925 /* Read a single sector to req->buffer + (512 * i) */
926 if (NFTL_readblock(nftl, block, buffer)) {
927 DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
934 DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
937 } else if (req->cmd == WRITE) {
938 DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
939 "(req->nr_sectors == %lx)\n", nsect, block,
941 #ifdef CONFIG_NFTL_RW
942 for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
943 /* Read a single sector to req->buffer + (512 * i) */
944 if (NFTL_writeblock(nftl, block, buffer)) {
945 DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
951 DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
953 res = 0; /* Writes always fail */
954 #endif /* CONFIG_NFTL_RW */
958 DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
964 DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
965 spin_lock_irq(&io_request_lock);
970 static int nftl_open(struct inode *ip, struct file *fp)
972 int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS;
973 struct NFTLrecord *thisNFTL;
974 thisNFTL = NFTLs[nftlnum];
976 DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
979 if (!thisNFTL && nftlnum == 0) {
980 request_module("docprobe");
981 thisNFTL = NFTLs[nftlnum];
985 DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n",
986 nftlnum, ip->i_rdev, ip, fp);
990 #ifndef CONFIG_NFTL_RW
991 if (fp->f_mode & FMODE_WRITE)
993 #endif /* !CONFIG_NFTL_RW */
995 thisNFTL->usecount++;
997 if (!get_mtd_device(thisNFTL->mtd, -1)) {
1005 static int nftl_release(struct inode *inode, struct file *fp)
1007 struct NFTLrecord *thisNFTL;
1009 thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
1011 DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
1013 if (thisNFTL->mtd->sync)
1014 thisNFTL->mtd->sync(thisNFTL->mtd);
1015 thisNFTL->usecount--;
1018 put_mtd_device(thisNFTL->mtd);
1022 #if LINUX_VERSION_CODE < 0x20326
1023 static struct file_operations nftl_fops = {
1028 release: nftl_release,
1032 static struct block_device_operations nftl_fops =
1034 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
1038 release: nftl_release,
1045 /****************************************************************************
1049 ****************************************************************************/
1051 static struct mtd_notifier nftl_notifier = {
1052 add: NFTL_notify_add,
1053 remove: NFTL_notify_remove
1056 extern char nftlmountrev[];
1058 int __init init_nftl(void)
1063 printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.1.1.1 $, nftlmount.c %s\n", nftlmountrev);
1066 if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
1067 printk("unable to register NFTL block device on major %d\n", MAJOR_NR);
1070 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
1072 /* set block size to 1kB each */
1073 for (i = 0; i < 256; i++) {
1074 nftl_blocksizes[i] = 1024;
1076 blksize_size[MAJOR_NR] = nftl_blocksizes;
1078 add_gendisk(&nftl_gendisk);
1081 register_mtd_user(&nftl_notifier);
1086 static void __exit cleanup_nftl(void)
1088 unregister_mtd_user(&nftl_notifier);
1089 unregister_blkdev(MAJOR_NR, "nftl");
1091 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1093 del_gendisk(&nftl_gendisk);
1096 module_init(init_nftl);
1097 module_exit(cleanup_nftl);
1099 MODULE_LICENSE("GPL");
1100 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
1101 MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");