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 $ */
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>
27 #include <linux/buffer_head.h>
30 #include <linux/kmod.h>
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
)
57 struct NFTLrecord
*nftl
;
62 DEBUG(MTD_DEBUG_LEVEL1
,"NFTL_setup\n");
64 for (i
= 0; i
< MAX_NFTLS
; i
++) {
65 if (!NFTLs
[i
] && firstfree
== -1)
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");
73 if (firstfree
== -1) {
74 printk(KERN_WARNING
"No more NFTL slot available\n");
78 nftl
= kmalloc(sizeof(struct NFTLrecord
), GFP_KERNEL
);
79 gd
= alloc_disk(1 << NFTL_PARTN_BITS
);
83 printk(KERN_WARNING
"Out of memory for NFTL data structures\n");
87 init_MUTEX(&nftl
->mutex
);
89 /* get physical parameters */
90 nftl
->EraseSize
= mtd
->erasesize
;
91 nftl
->nb_blocks
= mtd
->size
/ mtd
->erasesize
;
94 if (NFTL_mount(nftl
) < 0) {
95 printk(KERN_WARNING
"Could not mount NFTL device\n");
101 /* OK, it's a new one. Set up all the data structures. */
103 printk("Found new NFTL nftl%c\n", firstfree
+ 'a');
107 nftl
->cylinders
= 1024;
110 temp
= nftl
->cylinders
* nftl
->heads
;
111 nftl
->sectors
= nftl
->nr_sects
/ temp
;
112 if (nftl
->nr_sects
% temp
) {
114 temp
= nftl
->cylinders
* nftl
->sectors
;
115 nftl
->heads
= nftl
->nr_sects
/ temp
;
117 if (nftl
->nr_sects
% temp
) {
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
);
139 gd
->private_data
= nftl
;
140 gd
->queue
= &nftl_queue
;
144 static void NFTL_unsetup(int i
)
146 struct NFTLrecord
*nftl
= NFTLs
[i
];
148 DEBUG(MTD_DEBUG_LEVEL1
, "NFTL_unsetup %d\n", i
);
152 if (nftl
->ReplUnitTable
)
153 kfree(nftl
->ReplUnitTable
);
155 kfree(nftl
->EUNtable
);
156 del_gendisk(nftl
->disk
);
157 put_disk(nftl
->disk
);
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
);
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");
173 DEBUG(MTD_DEBUG_LEVEL3
, "mtd->read = %p, size = %d, erasesize = %d\n",
174 mtd
->read
, mtd
->size
, mtd
->erasesize
);
180 static void NFTL_notify_remove(struct mtd_info
*mtd
)
184 for (i
= 0; i
< MAX_NFTLS
; i
++) {
185 if (NFTLs
[i
] && NFTLs
[i
]->mtd
== mtd
)
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");
211 /* Scan for a free block */
213 if (nftl
->ReplUnitTable
[pot
] == BLOCK_FREE
) {
214 nftl
->LastFreeEUN
= 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
);
227 printk("Argh! No free blocks found! LastFreeEUN = %d, "
228 "FirstEUN = %d\n", nftl
->LastFreeEUN
,
229 le16_to_cpu(nftl
->MediaHdr
.FirstPhysicalEUN
));
232 } while (pot
!= nftl
->LastFreeEUN
);
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
;
245 unsigned int targetEUN
;
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
);
261 /* Scan to find the Erase Unit which holds the actual data for each
262 512-byte block within the Chain.
265 targetEUN
= BLOCK_NIL
;
266 while (thisEUN
<= nftl
->lastEUN
) {
267 unsigned int status
, foldmark
;
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
);
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
);
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 */
287 status
= oob
.b
.Status
| oob
.b
.Status1
;
288 BlockLastState
[block
] = status
;
292 BlockFreeFound
[block
] = 1;
296 if (!BlockFreeFound
[block
])
297 BlockMap
[block
] = thisEUN
;
300 "SECTOR_USED found after SECTOR_FREE "
301 "in Virtual Unit Chain %d for block %d\n",
305 if (!BlockFreeFound
[block
])
306 BlockMap
[block
] = BLOCK_NIL
;
309 "SECTOR_DELETED found after SECTOR_FREE "
310 "in Virtual Unit Chain %d for block %d\n",
317 printk("Unknown status for block %d in EUN %d: %x\n",
318 block
, thisEUN
, status
);
323 printk(KERN_WARNING
"Infinite loop in Virtual Unit Chain 0x%x\n",
328 thisEUN
= nftl
->ReplUnitTable
[thisEUN
];
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
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
],
348 BlockMap
[block
]== targetEUN
? "==" : "!=",
355 if (pendingblock
>= (thisVUC
* (nftl
->EraseSize
/ 512)) &&
356 pendingblock
< ((thisVUC
+ 1)* (nftl
->EraseSize
/ 512)) &&
357 BlockLastState
[pendingblock
- (thisVUC
* (nftl
->EraseSize
/ 512))] !=
359 DEBUG(MTD_DEBUG_LEVEL1
, "Pending write not free in EUN %d. "
360 "Folding out of place.\n", targetEUN
);
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.
378 "NFTL_findfreeblock(desperate) returns 0xffff.\n");
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.
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];
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
))) {
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
)
412 ret
= MTD_READECC(nftl
->mtd
, (nftl
->EraseSize
* BlockMap
[block
])
413 + (block
* 512), 512, &retlen
, movebuf
, (char *)&oob
);
415 ret
= MTD_READECC(nftl
->mtd
, (nftl
->EraseSize
* BlockMap
[block
])
416 + (block
* 512), 512, &retlen
,
417 movebuf
, (char *)&oob
);
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
) {
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
;
456 /* correctly erased : mark it as free */
457 nftl
->ReplUnitTable
[thisEUN
] = BLOCK_FREE
;
463 /* Make this the new start of chain for thisVUC */
464 nftl
->ReplUnitTable
[targetEUN
] = BLOCK_NIL
;
465 nftl
->EUNtable
[thisVUC
] = 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
;
483 for (chain
= 0; chain
< le32_to_cpu(nftl
->MediaHdr
.FormattedSize
) / nftl
->EraseSize
; chain
++) {
484 EUN
= nftl
->EUNtable
[chain
];
487 while (EUN
<= nftl
->lastEUN
) {
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",
495 if (thislen
> 0xff10) {
496 /* Actually, don't return failure. Just ignore this chain and
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");
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
)
525 u16 thisVUC
= block
/ (nftl
->EraseSize
/ 512);
526 unsigned int writeEUN
;
527 unsigned long blockofs
= (block
* 512) & (nftl
->EraseSize
-1);
529 int silly
, silly2
= 3;
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
541 writeEUN
= nftl
->EUNtable
[thisVUC
];
543 while (writeEUN
<= nftl
->lastEUN
) {
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
;
566 // Invalid block. Don't use it any more. Must implement.
572 "Infinite loop in Virtual Unit Chain 0x%x\n",
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");
619 //printk("Restarting scan\n");
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 */
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
);
667 printk(KERN_WARNING
"Error folding to make room for Virtual Unit Chain 0x%x\n",
672 static int NFTL_writeblock(struct NFTLrecord
*nftl
, unsigned block
, char *buffer
)
675 unsigned long blockofs
= (block
* 512) & (nftl
->EraseSize
- 1);
679 writeEUN
= NFTL_findwriteunit(nftl
, block
);
681 if (writeEUN
== BLOCK_NIL
) {
683 "NFTL_writeblock(): Cannot find block to write to\n");
684 /* If we _still_ haven't got a block to use, we're screwed */
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 */
694 #endif /* CONFIG_NFTL_RW */
696 static int NFTL_readblock(struct NFTLrecord
*nftl
, unsigned block
, char *buffer
)
699 u16 thisEUN
= nftl
->EUNtable
[block
/ (nftl
->EraseSize
/ 512)];
700 unsigned long blockofs
= (block
* 512) & (nftl
->EraseSize
- 1);
702 int silly
= MAX_LOOPS
;
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
;
714 status
= bci
.Status
| bci
.Status1
;
718 /* no modification of a sector should follow a free sector */
721 lastgoodEUN
= BLOCK_NIL
;
724 lastgoodEUN
= thisEUN
;
729 printk("Unknown status for block %d in EUN %d: %x\n",
730 block
, thisEUN
, status
);
735 printk(KERN_WARNING
"Infinite loop in Virtual Unit Chain 0x%x\n",
736 block
/ (nftl
->EraseSize
/ 512));
739 thisEUN
= nftl
->ReplUnitTable
[thisEUN
];
744 if (lastgoodEUN
== BLOCK_NIL
) {
745 /* the requested block is not on the media, return all 0x00 */
746 memset(buffer
, 0, 512);
748 loff_t ptr
= (lastgoodEUN
* nftl
->EraseSize
) + blockofs
;
751 if (MTD_READECC(nftl
->mtd
, ptr
, 512, &retlen
, buffer
, eccbuf
))
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
;
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;
771 fsync_bdev(inode
->i_bdev
);
772 invalidate_bdev(inode
->i_bdev
, 0);
774 nftl
->mtd
->sync(nftl
->mtd
);
781 void nftl_request(struct request_queue
*q
)
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");
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
);
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");
829 DEBUG(MTD_DEBUG_LEVEL2
,"NFTL read request completed OK\n");
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
,
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");
846 DEBUG(MTD_DEBUG_LEVEL2
,"NFTL write request completed OK\n");
848 res
= 0; /* Writes always fail */
849 #endif /* CONFIG_NFTL_RW */
853 DEBUG(MTD_DEBUG_LEVEL0
, "NFTL unknown request\n");
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");
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");
879 #ifndef CONFIG_NFTL_RW
880 if (fp
->f_mode
& FMODE_WRITE
)
882 #endif /* !CONFIG_NFTL_RW */
884 if (!get_mtd_device(thisNFTL
->mtd
, -1))
885 return /* -E'SBUGGEREDOFF */ -ENXIO
;
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
);
903 static struct block_device_operations nftl_fops
=
905 .owner
= THIS_MODULE
,
907 .release
= nftl_release
,
911 /****************************************************************************
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)
929 printk(KERN_INFO
"NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev
);
932 if (register_blkdev(MAJOR_NR
, "nftl"))
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
);
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");