2 /* Linux driver for NAND Flash Translation Layer */
3 /* (c) 1999 Machine Vision Holdings, Inc. */
4 /* Author: David Woodhouse <dwmw2@infradead.org> */
5 /* $Id: nftl.c,v 1.35 2000/07/06 14:35:01 dwmw2 Exp $ */
8 The contents of this file are distributed under the GNU Public
9 Licence version 2 ("GPL"). The legal note below refers only to the
10 _use_ of the code in some jurisdictions, and does not in any way
11 affect the copying, distribution and modification of this code,
12 which is permitted under the terms of the GPL.
14 Section 0 of the GPL says:
16 "Activities other than copying, distribution and modification are not
17 covered by this License; they are outside its scope."
19 You may copy, distribute and modify this code to your hearts'
20 content - it's just that in some jurisdictions, you may only _use_
21 it under the terms of the licence below. This puts it in a similar
22 situation to the ISDN code, which you may need telco approval to
23 use, and indeed any code which has uses that may be restricted in
24 law. For example, certain malicious uses of the networking stack
25 may be illegal, but that doesn't prevent the networking code from
28 In fact the ISDN case is worse than this, because modification of
29 the code automatically invalidates its approval. Modificiation,
30 unlike usage, _is_ one of the rights which is protected by the
31 GPL. Happily, the law in those places where approval is required
32 doesn't actually prevent you from modifying the code - it's just
33 that you may not be allowed to _use_ it once you've done so - and
34 because usage isn't addressed by the GPL, that's just fine.
39 LEGAL NOTE: The NFTL format is patented by M-Systems. They have
40 granted a licence for its use with their DiskOnChip products:
42 "M-Systems grants a royalty-free, non-exclusive license under
43 any presently existing M-Systems intellectual property rights
44 necessary for the design and development of NFTL-compatible
45 drivers, file systems and utilities to use the data formats with,
46 and solely to support, M-Systems' DiskOnChip products"
48 A signed copy of this agreement from M-Systems is kept on file by
49 Red Hat UK Limited. In the unlikely event that you need access to it,
50 please contact dwmw2@redhat.com for assistance. */
55 #define DEBUGLVL debug
58 #include <linux/config.h>
59 #include <linux/kernel.h>
60 #include <linux/module.h>
61 #include <asm/errno.h>
63 #include <asm/uaccess.h>
64 #include <linux/miscdevice.h>
65 #include <linux/pci.h>
66 #include <linux/delay.h>
67 #include <linux/malloc.h>
68 #include <linux/sched.h>
69 #include <linux/init.h>
70 #include <linux/mtd/mtd.h>
71 #include <linux/mtd/nftl.h>
72 #include <linux/mtd/compatmac.h>
74 #undef WE_KNOW_WTF_THIS_DOES_NOT_WORK
76 /* NFTL block device stuff */
77 #define MAJOR_NR NFTL_MAJOR
78 #define DEVICE_REQUEST nftl_request
79 #define DEVICE_OFF(device)
80 #ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
81 #define LOCAL_END_REQUEST
83 #include <linux/blk.h>
84 #include <linux/hdreg.h>
87 #ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
89 static void nftl_end_request(struct request
*req
, int res
)
91 req
->sector
+= req
->current_nr_sectors
;
92 req
->nr_sectors
-= req
->current_nr_sectors
;
94 if (end_that_request_first( req
, res
, "nftl" ))
96 end_that_request_last( req
);
101 static int debug
= NFTL_DEBUG
;
102 MODULE_PARM(debug
, "i");
107 /* Linux-specific block device functions */
109 /* I _HATE_ the Linux block device setup more than anything else I've ever
110 * encountered, except ...
113 static int nftl_sizes
[256]={0,};
114 static int nftl_blocksizes
[256] = {0,};
116 /* .. for the Linux partition table handling. */
118 struct hd_struct part_table
[256] = {{0,0},};
120 #if LINUX_VERSION_CODE < 0x20328
121 static void dummy_init (struct gendisk
*crap
)
125 static struct gendisk nftl_gendisk
= {
126 NFTL_MAJOR
, /* Major number */
127 "nftl", /* Major name */
128 4, /* Bits to shift to get real from partition */
129 15, /* Number of partitions per real */
130 #if LINUX_VERSION_CODE < 0x20328
131 MAX_NFTLS
, /* maximum number of real */
132 dummy_init
, /* init function */
134 part_table
, /* hd struct */
135 nftl_sizes
, /* block sizes */
137 NULL
, /* internal use, not presently used */
142 struct NFTLrecord
*NFTLs
[MAX_NFTLS
] = {NULL
};
144 static void NFTL_setup(struct mtd_info
*mtd
, unsigned long ofs
,
145 struct NFTLMediaHeader
*hdr
)
148 struct NFTLrecord
*thisNFTL
;
152 DEBUG(1,"NFTL_setup\n");
154 for (i
=0; i
< MAX_NFTLS
; i
++) {
155 if (!NFTLs
[i
] && firstfree
==-1)
157 else if (NFTLs
[i
] && NFTLs
[i
]->mtd
== mtd
&&
158 NFTLs
[i
]->MediaHdr
.FirstPhysicalEUN
== hdr
->FirstPhysicalEUN
) {
159 /* This is a Spare Media Header for an NFTL we've already found */
160 DEBUG(1, "Spare Media Header for NFTL %d found at %lx\n",i
, ofs
);
161 NFTLs
[i
]->SpareMediaUnit
= ofs
/ mtd
->erasesize
;
167 /* OK, it's a new one. Set up all the data structures. */
169 printk("Found new NFTL nftl%c at offset %lx\n",firstfree
+ 'a', ofs
);
171 if (hdr
->UnitSizeFactor
!= 0xff) {
172 printk("Sorry, we don't support UnitSizeFactor of != 1 yet\n");
176 thisNFTL
= kmalloc(sizeof(struct NFTLrecord
), GFP_KERNEL
);
178 printk(KERN_WARNING
"Out of memory for NFTL data structures\n");
181 init_MUTEX(&thisNFTL
->mutex
);
182 thisNFTL
->EraseSize
= mtd
->erasesize
;
183 memcpy(&thisNFTL
->MediaHdr
, hdr
, sizeof(*hdr
));
185 thisNFTL
->MediaUnit
= ofs
/ mtd
->erasesize
;
186 thisNFTL
->SpareMediaUnit
= 0xffff;
187 thisNFTL
->numvunits
= le32_to_cpu(thisNFTL
->MediaHdr
.FormattedSize
) / 8192;
188 thisNFTL
->nr_sects
= thisNFTL
->numvunits
* (thisNFTL
->EraseSize
/ 512);
189 thisNFTL
->usecount
= 0;
191 thisNFTL
->cylinders
= 1024;
192 thisNFTL
->heads
= 16;
194 temp
= thisNFTL
->cylinders
* thisNFTL
->heads
;
195 thisNFTL
->sectors
= thisNFTL
->nr_sects
/ temp
;
197 if (thisNFTL
->nr_sects
% temp
) {
200 temp
= thisNFTL
->cylinders
* thisNFTL
->sectors
;
201 thisNFTL
->heads
= thisNFTL
->nr_sects
/ temp
;
203 if (thisNFTL
->nr_sects
& temp
) {
205 temp
= thisNFTL
->heads
* thisNFTL
->sectors
;
207 thisNFTL
->cylinders
= thisNFTL
->nr_sects
/ temp
;
210 if (thisNFTL
->nr_sects
!= thisNFTL
->heads
* thisNFTL
->cylinders
*
212 printk(KERN_WARNING
"Cannot calculate an NFTL geometry to match size of 0x%lx.\n", thisNFTL
->nr_sects
);
213 printk(KERN_WARNING
"Using C:%d H:%d S:%d (== %lx sects)\n",
214 thisNFTL
->cylinders
, thisNFTL
->heads
,
216 (long)thisNFTL
->cylinders
* (long)thisNFTL
->heads
*
217 (long)thisNFTL
->sectors
);
220 * thisNFTL->nr_sects = thisNFTL->heads * thisNFTL->cylinders * thisNFTL->sectors;
225 thisNFTL
->EUNtable
= kmalloc( 2 * thisNFTL
->numvunits
,
227 if (!thisNFTL
->EUNtable
) {
232 memset(thisNFTL
->EUNtable
, 0xff, 2 * thisNFTL
->numvunits
);
234 thisNFTL
->VirtualUnitTable
= kmalloc( 2 * le16_to_cpu(thisNFTL
->MediaHdr
.NumEraseUnits
) , GFP_KERNEL
);
235 if (!thisNFTL
->VirtualUnitTable
) {
237 kfree(thisNFTL
->EUNtable
);
241 memset(thisNFTL
->VirtualUnitTable
, 0xff, 2 * le16_to_cpu(thisNFTL
->MediaHdr
.NumEraseUnits
));
243 thisNFTL
->ReplUnitTable
= kmalloc( 2 * le16_to_cpu(thisNFTL
->MediaHdr
.NumEraseUnits
) , GFP_KERNEL
);
244 if (!thisNFTL
->ReplUnitTable
) {
246 kfree(thisNFTL
->VirtualUnitTable
);
247 kfree(thisNFTL
->EUNtable
);
251 memset(thisNFTL
->ReplUnitTable
, 0xff, 2 *le16_to_cpu(thisNFTL
->MediaHdr
.NumEraseUnits
) );
253 /* Ought to check the media header for bad blocks */
254 thisNFTL
->lastEUN
= le16_to_cpu(thisNFTL
->MediaHdr
.NumEraseUnits
) +
255 le16_to_cpu(thisNFTL
->MediaHdr
.FirstPhysicalEUN
) - 1;
256 thisNFTL
->numfreeEUNs
= 0;
258 /* Scan each physical Erase Unit for validity and to find the
259 Virtual Erase Unit Chain to which it belongs */
261 for (i
=le16_to_cpu(thisNFTL
->MediaHdr
.FirstPhysicalEUN
);
262 i
<= thisNFTL
->lastEUN
; i
++) {
267 ofs
= i
* thisNFTL
->EraseSize
;
269 MTD_READOOB(mtd
, (i
* thisNFTL
->EraseSize
) + 512 + 8, 8, &retlen
, (char *)&uci
);
271 if (uci
.b
.EraseMark
!= cpu_to_le16(0x3c69) ||
272 uci
.b
.EraseMark1
!= cpu_to_le16(0x3c69)) {
273 printk("EUN %d: EraseMark not 0x3c69 (0x%4.4x 0x%4.4x instead)\n",
274 i
, le16_to_cpu(uci
.b
.EraseMark
), le16_to_cpu(uci
.b
.EraseMark1
));
275 thisNFTL
->VirtualUnitTable
[i
] = 0x7fff;
276 thisNFTL
->ReplUnitTable
[i
] = 0xffff;
280 MTD_READOOB(mtd
, (i
* thisNFTL
->EraseSize
) + 8, 8, &retlen
, (u_char
*)&uci
);
282 if (uci
.a
.VirtUnitNum
!= uci
.a
.SpareVirtUnitNum
)
283 printk("EUN %d: VirtualUnitNumber (%x) != SpareVirtualUnitNumber (%x)\n",
284 i
, le16_to_cpu(uci
.a
.VirtUnitNum
),
285 le16_to_cpu(uci
.a
.SpareVirtUnitNum
));
287 if (uci
.a
.ReplUnitNum
!= uci
.a
.SpareReplUnitNum
)
288 printk("EUN %d: ReplacementUnitNumber (%x) != SpareReplacementUnitNumber (%x)\n",
289 i
, le16_to_cpu(uci
.a
.ReplUnitNum
),
290 le16_to_cpu(uci
.a
.SpareReplUnitNum
));
292 /* We don't actually _do_ anything about the above, just whinge */
294 thisNFTL
->VirtualUnitTable
[i
] = le16_to_cpu(uci
.a
.VirtUnitNum
);
295 thisNFTL
->ReplUnitTable
[i
] = le16_to_cpu(uci
.a
.ReplUnitNum
);
297 /* if (!(VUN & 0x8000) && VUN < (arraybounds)).. optimises to: */
298 if (le16_to_cpu(uci
.a
.VirtUnitNum
) < thisNFTL
->numvunits
)
299 thisNFTL
->EUNtable
[le16_to_cpu(uci
.a
.VirtUnitNum
) & 0x7fff] = i
;
301 if (uci
.a
.VirtUnitNum
== 0xffff) {
303 thisNFTL
->LastFreeEUN
= i
;
304 thisNFTL
->numfreeEUNs
++;
308 NFTLs
[firstfree
] = thisNFTL
;
309 thisNFTL
->LastFreeEUN
= le16_to_cpu(thisNFTL
->MediaHdr
.FirstPhysicalEUN
);
311 //#define PSYCHO_DEBUG
313 for (i
=0; i
< 10/* thisNFTL->numvunits*/; i
++) {
314 u16 curEUN
= thisNFTL
->EUNtable
[i
];
317 printk("Virtual Unit #%d: ",i
);
318 if (!curEUN
|| curEUN
== 0xffff) {
319 printk("Not present\n");
322 printk("%d", curEUN
);
324 while ((curEUN
= thisNFTL
->ReplUnitTable
[curEUN
]) != 0xffff && --sillycount
) {
325 printk(", %d", curEUN
& 0xffff);
332 /* OK. Now we deal with the fact that we're in the real world. Sometimes
333 things don't actually happen the way they're supposed to. Find, fix,
334 and whinge about the most common deviations from spec that we have
335 been known to encounter.
337 /* Except that I haven't implemented that bit yet :) */
339 /* Finally, set up the block device sizes */
340 nftl_sizes
[firstfree
* 16]=thisNFTL
->nr_sects
;
341 // nftl_blocksizes[firstfree*16] = 512;
342 part_table
[firstfree
* 16].nr_sects
= thisNFTL
->nr_sects
;
343 #if LINUX_VERSION_CODE < 0x20328
344 resetup_one_dev(&nftl_gendisk
, firstfree
);
346 grok_partitions(&nftl_gendisk
, firstfree
, 1<<4, thisNFTL
->nr_sects
);
352 static void NFTL_unsetup(int i
)
354 struct NFTLrecord
*thisNFTL
= NFTLs
[i
];
356 DEBUG(1, "NFTL_unsetup %d\n", i
);
360 if (thisNFTL
->VirtualUnitTable
)
361 kfree(thisNFTL
->VirtualUnitTable
);
362 if (thisNFTL
->ReplUnitTable
)
363 kfree(thisNFTL
->ReplUnitTable
);
364 if (thisNFTL
->EUNtable
)
365 kfree(thisNFTL
->EUNtable
);
373 /* Search the MTD device for NFTL partitions */
374 static void NFTL_notify_add(struct mtd_info
*mtd
)
378 struct NFTLMediaHeader hdr
;
380 DEBUG(1, "NFTL_notify_add for %s\n", mtd
->name
);
383 if (!mtd
->read_oob
) /* If this MTD doesn't have out-of-band data,
384 then there's no point continuing */
386 DEBUG(1, "No OOB data, quitting\n");
389 DEBUG(3, "mtd->read = %p,size = %d, erasesize = %d\n",
390 mtd
->read
, mtd
->size
, mtd
->erasesize
);
391 for (ofs
= 0; ofs
< mtd
->size
; ofs
+= mtd
->erasesize
) {
393 MTD_READ(mtd
, ofs
, sizeof(hdr
), &retlen
, (u_char
*)&hdr
);
395 if (retlen
< sizeof(hdr
))
400 if (!strncmp(hdr
.DataOrgID
, "ANAND", 6)) {
401 DEBUG(2, "Valid NFTL partition at ofs %ld\n", ofs
);
402 NFTL_setup(mtd
, ofs
, &hdr
);
405 DEBUG(3,"No valid NFTL Partition at ofs %d\n", ofs
);
406 for(i
= 0; i
< 6; i
++) {
407 DEBUG(3,"%x, ", hdr
.DataOrgID
[i
]);
409 DEBUG(3," = %s\n", hdr
.DataOrgID
);
410 DEBUG(3,"%d, %d, %d, %d\n", hdr
.NumEraseUnits
, hdr
.FirstPhysicalEUN
,
411 hdr
.FormattedSize
, hdr
.UnitSizeFactor
);
419 static void NFTL_notify_remove(struct mtd_info
*mtd
)
423 for (i
=0; i
< MAX_NFTLS
; i
++) {
424 if (NFTLs
[i
] && NFTLs
[i
]->mtd
== mtd
)
430 #ifdef CONFIG_NFTL_RW
432 /* Actual NFTL access routines */
435 static u16
NFTL_findfreeblock( struct NFTLrecord
*thisNFTL
, int desperate
)
437 /* For a given Virtual Unit Chain: find or create a free block and
438 add it to the chain */
439 /* We're passed the number of the last EUN in the chain, to save us from
440 having to look it up again */
442 u16 pot
= thisNFTL
->LastFreeEUN
;
445 /* Normally, we force a fold to happen before we run out of free blocks completely */
447 if (!desperate
&& thisNFTL
->numfreeEUNs
< 2) {
448 // printk("NFTL_findfreeblock: there are too few free EUNs\n");
452 /* Scan for a free block */
455 if (thisNFTL
->VirtualUnitTable
[pot
] == 0xffff) {
456 thisNFTL
->LastFreeEUN
= pot
;
457 thisNFTL
->numfreeEUNs
--;
461 if (++pot
> thisNFTL
->lastEUN
)
462 pot
= le16_to_cpu(thisNFTL
->MediaHdr
.FirstPhysicalEUN
);
465 printk("Tell Dave he fucked up. LastFreeEUN = %d, FirstEUN = %d\n",
466 thisNFTL
->LastFreeEUN
, le16_to_cpu(thisNFTL
->MediaHdr
.FirstPhysicalEUN
));
470 } while (pot
!= thisNFTL
->LastFreeEUN
);
479 static u16
NFTL_foldchain (struct NFTLrecord
*thisNFTL
, u16 thisVUC
, unsigned pendingblock
)
481 u16 BlockMap
[thisNFTL
->EraseSize
/ 512];
482 unsigned char BlockLastState
[thisNFTL
->EraseSize
/ 512];
483 unsigned char BlockFreeFound
[thisNFTL
->EraseSize
/ 512];
487 u16 targetEUN
= 0xffff;
491 memset(BlockMap
, 0xff, sizeof(BlockMap
));
492 memset(BlockFreeFound
, 0, sizeof(BlockFreeFound
));
494 thisEUN
= thisNFTL
->EUNtable
[thisVUC
];
496 if (thisEUN
== 0xffff) {
497 printk(KERN_WARNING
"Trying to fold non-existent Virtual Unit Chain %d!\n", thisVUC
);
501 /* Scan to find the Erase Unit which holds the actual data for each
502 512-byte block within the Chain.
505 while( thisEUN
<= thisNFTL
->lastEUN
) {
510 for (block
= 0 ; block
< thisNFTL
->EraseSize
/ 512; block
++) {
512 MTD_READOOB(thisNFTL
->mtd
, (thisEUN
* thisNFTL
->EraseSize
) + (block
* 512),16 , &retlen
, (char *)&oob
);
515 if (oob
.u
.c
.WriteInh
!= 0xffffffff) {
516 printk("Write Inhibited on EUN %d\n", thisEUN
);
519 /* There's no other reason not to do inplace,
520 except ones that come later. So we don't need
521 to preserve inplace */
526 BlockLastState
[block
] = (unsigned char) oob
.b
.Status
& 0xff;
528 switch(oob
.b
.Status
) {
529 case __constant_cpu_to_le16(BLOCK_FREE
):
530 BlockFreeFound
[block
]=1;
533 case __constant_cpu_to_le16(BLOCK_USED
):
534 if (!BlockFreeFound
[block
])
535 BlockMap
[block
] = thisEUN
;
537 printk(KERN_WARNING
"BLOCK_USED found after BLOCK_FREE in Virtual Unit Chain %d for block %d\n", thisVUC
, block
);
539 case __constant_cpu_to_le16(BLOCK_IGNORE
):
540 case __constant_cpu_to_le16(BLOCK_DELETED
):
543 printk("Unknown status for block %d in EUN %d: %x\n",block
,thisEUN
, oob
.b
.Status
);
548 printk(KERN_WARNING
"Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC
);
552 thisEUN
= thisNFTL
->ReplUnitTable
[thisEUN
] & 0x7fff;
556 /* We're being asked to be a fold-in-place. Check
557 that all blocks are either present or BLOCK_FREE
558 in the target block. If not, we're going to have
559 to fold out-of-place anyway.
562 for (block
= 0; block
< thisNFTL
->EraseSize
/ 512 ; block
++) {
564 if (BlockLastState
[block
] != (unsigned char) (cpu_to_le16(BLOCK_FREE
) & 0xff) &&
565 BlockMap
[block
] != targetEUN
) {
566 DEBUG(1, "Setting inplace to 0. VUC %d, block %d was %x lastEUN, and is in EUN %d (%s) %d\n",
567 thisVUC
, block
, BlockLastState
[block
], BlockMap
[block
] , BlockMap
[block
]==targetEUN
?"==":"!=", targetEUN
);
574 if ( pendingblock
>= (thisVUC
* (thisNFTL
->EraseSize
/ 512)) &&
575 pendingblock
< ((thisVUC
+ 1)* (thisNFTL
->EraseSize
/ 512)) &&
576 BlockLastState
[ pendingblock
- (thisVUC
* (thisNFTL
->EraseSize
/ 512))] !=
577 (unsigned char) (cpu_to_le16(BLOCK_FREE
) & 0xff)) {
578 DEBUG(1, "Pending write not free in EUN %d. Folding out of place.\n", targetEUN
);
585 DEBUG(1, "Cannot fold Virtual Unit Chain %d in place. Trying out-of-place\n", thisVUC
);
586 /* We need to find a targetEUN to fold into. */
587 targetEUN
= NFTL_findfreeblock(thisNFTL
, 1);
588 if (targetEUN
== 0xffff) {
589 /* Ouch. Now we're screwed. We need to do a
590 fold-in-place of another chain to make room
591 for this one. We need a better way of selecting
592 which chain to fold, because makefreeblock will
593 only ask us to fold the same one again.
595 printk(KERN_WARNING
"NFTL_findfreeblock(desperate) returns 0xffff.\n");
602 /* OK. We now know the location of every block in the Virtual Unit Chain,
603 and the Erase Unit into which we are supposed to be copying.
607 DEBUG(1,"Folding chain %d into unit %d\n", thisVUC
, targetEUN
);
609 for (block
= 0; block
< thisNFTL
->EraseSize
/ 512 ; block
++) {
610 unsigned char movebuf
[512];
614 memset(&oob
, 0xff, sizeof(oob
));
616 /* If it's in the target EUN already, or if it's pending write, do nothing */
617 if (BlockMap
[block
] == targetEUN
||(pendingblock
== (thisVUC
* (thisNFTL
->EraseSize
/ 512) + block
))) {
618 /* Except if it's the first block, in which case we have to
619 set the UnitNumbers */
622 thisNFTL
->mtd
->read_oob(thisNFTL
->mtd
, (thisNFTL
->EraseSize
* targetEUN
) ,
623 16, &retlen
, (char *)&oob
);
625 // printk("Setting VirtUnitNum on EUN %d to %x, was %x\n", targetEUN, thisVUC,
626 // le16_to_cpu(oob.u.a.VirtUnitNum));
628 oob
.u
.a
.VirtUnitNum
= oob
.u
.a
.SpareVirtUnitNum
= cpu_to_le16(thisVUC
& 0x7fff);
630 thisNFTL
->mtd
->write_oob(thisNFTL
->mtd
, (thisNFTL
->EraseSize
* targetEUN
) ,
631 16, &retlen
, (char *)&oob
);
636 oob
.b
.Status
= BLOCK_USED
;
640 oob
.u
.a
.VirtUnitNum
= oob
.u
.a
.SpareVirtUnitNum
= cpu_to_le16(thisVUC
& 0x7fff);
641 // printk("Setting VirtUnitNum on EUN %d to %x\n", targetEUN, thisVUC);
643 oob
.u
.a
.ReplUnitNum
= oob
.u
.a
.SpareReplUnitNum
= 0xffff;
647 oob
.u
.b
.WearInfo
= cpu_to_le32(3); // We don't use this, but M-Systems' drivers do
648 oob
.u
.b
.EraseMark
= oob
.u
.b
.EraseMark1
= cpu_to_le16(0x3c69);
653 oob
.u
.c
.WriteInh
= 0xffffffff;
654 oob
.u
.c
.unused
= 0xffffffff;
656 if (thisNFTL
->mtd
->read_ecc(thisNFTL
->mtd
, (thisNFTL
->EraseSize
* BlockMap
[block
]) + (block
* 512),
657 512, &retlen
, movebuf
, (char *)&oob
) == -EIO
) {
658 if (thisNFTL
->mtd
->read_ecc(thisNFTL
->mtd
, (thisNFTL
->EraseSize
* BlockMap
[block
]) + (block
* 512),
659 512, &retlen
, movebuf
, (char *)&oob
) != -EIO
)
660 printk("Error went away on retry.\n");
663 thisNFTL
->mtd
->write_ecc(thisNFTL
->mtd
, (thisNFTL
->EraseSize
* targetEUN
) + (block
* 512),
664 512, &retlen
, movebuf
, (char *)&oob
);
667 /* FIXME: Add some error checking.... */
668 thisNFTL
->mtd
->write_oob(thisNFTL
->mtd
, (thisNFTL
->EraseSize
* targetEUN
) + (block
* 512),
669 16, &retlen
, (char *)&oob
);
673 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
675 /* At this point, we have two different chains for this Virtual Unit, and no way to tell
676 them apart. If we crash now, we get confused. However, both contain the same data, so we
677 shouldn't actually lose data in this case. It's just that when we load up on a medium which
678 has duplicate chains, we need to free one of the chains because it's not necessary any more.
682 thisEUN
= thisNFTL
->EUNtable
[thisVUC
];
684 DEBUG(1,"Want to erase\n");
685 /* For each block in the old chain (except the targetEUN of course),
686 free it and make it available for future use */
688 while( thisEUN
<= thisNFTL
->lastEUN
&& thisEUN
!= targetEUN
) {
690 struct erase_info
*instr
;
693 instr
= kmalloc(sizeof(struct erase_info
), GFP_KERNEL
);
695 printk(KERN_WARNING
"Out of memory for struct erase_info\n");
699 thisEUN
= thisNFTL
->ReplUnitTable
[EUNtmp
] & 0x7fff;
700 thisNFTL
->VirtualUnitTable
[EUNtmp
] = 0x7fff;
701 thisNFTL
->ReplUnitTable
[EUNtmp
] = 0xffff;
703 memset(instr
, 0, sizeof(struct erase_info
));
704 instr
->addr
= thisEUN
* thisNFTL
->EraseSize
;
705 instr
->len
= thisNFTL
->EraseSize
;
707 MTD_ERASE(thisNFTL
->mtd
, instr
);
708 /* This is an async interface. Or will be. At which point
709 this code will break. */
712 MTD_READOOB(thisNFTL
->mtd
, (thisEUN
* thisNFTL
->EraseSize
) + 512, 16, &retlen
, (char *)&oob
);
714 printk("After erasing, EUN %d contains: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
715 thisEUN
, oob
.b
.ECCSig
[0],
722 memset(&oob
, 0xff, sizeof(oob
));
723 oob
.u
.b
.WearInfo
= cpu_to_le32(3);
724 oob
.u
.b
.EraseMark
= oob
.u
.b
.EraseMark1
= cpu_to_le16(0x3c69);
726 MTD_WRITEOOB(thisNFTL
->mtd
, (thisEUN
* thisNFTL
->EraseSize
) + 512, 16, &retlen
, (char *)&oob
);
730 thisEUN
= thisNFTL
->ReplUnitTable
[EUNtmp
] & 0x7fff;
731 thisNFTL
->VirtualUnitTable
[EUNtmp
] = 0xffff;
732 thisNFTL
->ReplUnitTable
[EUNtmp
] = 0xffff;
734 thisNFTL
->numfreeEUNs
++;
738 // shifted upwards: thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff;
742 /* Make this the new start of chain for thisVUC */
743 thisNFTL
->VirtualUnitTable
[targetEUN
] = thisVUC
;
744 thisNFTL
->ReplUnitTable
[targetEUN
] = 0xffff;
746 thisNFTL
->EUNtable
[thisVUC
] = targetEUN
;
751 u16
NFTL_makefreeblock( struct NFTLrecord
*thisNFTL
, unsigned pendingblock
)
753 /* This is the part that needs some cleverness applied.
754 For now, I'm doing the minimum applicable to actually
755 get the thing to work.
756 Wear-levelling and other clever stuff needs to be implemented
757 and we also need to do some assessment of the results when
758 the system loses power half-way through the routine.
761 u16 LongestChain
= 0;
762 u16 ChainLength
= 0, thislen
;
766 for (chain
=0; chain
< thisNFTL
->MediaHdr
.FormattedSize
/ thisNFTL
->EraseSize
; chain
++) {
767 EUN
= thisNFTL
->EUNtable
[chain
];
771 while (EUN
<= thisNFTL
->lastEUN
) {
773 // printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
774 EUN
= thisNFTL
->ReplUnitTable
[EUN
] & 0x7fff;
775 if (thislen
> 0xff00) {
776 printk("Endless loop in Virtual Chain %d: Unit %x\n", chain
, EUN
);
778 if (thislen
> 0xff10) {
779 /* Actually, don't return failure. Just ignore this chain and
788 if (thislen
> ChainLength
) {
789 // printk("New longest chain is %d with length %d\n", chain, thislen);
790 ChainLength
= thislen
;
791 LongestChain
= chain
;
795 if (ChainLength
< 2) {
796 printk(KERN_WARNING
"No Virtual Unit Chains available for folding. Failing request\n");
800 return NFTL_foldchain (thisNFTL
, LongestChain
, pendingblock
);
803 /* NFTL_findwriteunit: Return the unit number into which we can write
804 for this block. Make it available if it isn't already
807 static inline u16
NFTL_findwriteunit(struct NFTLrecord
*thisNFTL
, unsigned block
)
810 u16 thisVUC
= block
/ (thisNFTL
->EraseSize
/ 512);
812 unsigned long blockofs
= (block
* 512) & (thisNFTL
->EraseSize
-1);
814 int silly
= 0x10000, silly2
= 3;
820 /* Scan the media to find a unit in the VUC which has
821 a free space for the block in question.
824 /* This condition catches the 0x[7f]fff cases, as well as
825 being a sanity check for past-end-of-media access
828 writeEUN
= thisNFTL
->EUNtable
[thisVUC
];
830 while(writeEUN
<= thisNFTL
->lastEUN
) {
836 MTD_READOOB(thisNFTL
->mtd
, (writeEUN
* thisNFTL
->EraseSize
)
837 + blockofs
,8, &retlen
, (char *)&bci
);
840 printk("Status of block %d in EUN %d is %x\n", block
, writeEUN
, le16_to_cpu(bci
.Status
));
843 case __constant_cpu_to_le16(BLOCK_FREE
):
846 case __constant_cpu_to_le16(BLOCK_DELETED
):
847 case __constant_cpu_to_le16(BLOCK_USED
):
848 case __constant_cpu_to_le16(BLOCK_IGNORE
):
851 // Invalid block. Don't use it any more. Must implement.
856 printk(KERN_WARNING
"Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC
);
860 /* Skip to next block in chain */
862 writeEUN
= thisNFTL
->ReplUnitTable
[writeEUN
] & 0x7fff;
865 /* OK. We didn't find one in the existing chain, or there
866 is no existing chain. */
868 /* Try to find an already-free block */
870 writeEUN
= NFTL_findfreeblock(thisNFTL
, 0);
872 if (writeEUN
== 0xffff) {
873 /* That didn't work - there were no free blocks just
874 waiting to be picked up. We're going to have to fold
875 a chain to make room.
878 /* First remember the start of this chain */
879 // u16 startEUN = thisNFTL->EUNtable[thisVUC];
881 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
882 writeEUN
= NFTL_makefreeblock(thisNFTL
, block
);
884 if (writeEUN
== 0xffff) {
885 /* Ouch. This should never happen - we should
886 always be able to make some room somehow.
887 If we get here, we've allocated more storage
888 space than actual media, or our makefreeblock
889 routine is missing something.
891 printk(KERN_WARNING
"Cannot make free space.\n");
894 // printk("Restarting scan\n");
899 if (startEUN
!= thisNFTL
->EUNtable
[thisVUC
]) {
900 /* The fold operation has moved the chain
901 that we're looking at. Start the scan again.
908 /* We've found a free block. Insert it into the chain. */
910 if (lastEUN
!= 0xffff) {
911 /* Addition to an existing chain. Make the previous
912 last block in the chain point to this one.
915 //printk("Linking EUN %d to EUN %d in VUC %d\n",
916 // lastEUN, writeEUN, thisVUC);
917 /* Both in our cache... */
918 thisNFTL
->ReplUnitTable
[lastEUN
] = writeEUN
;
921 /* ... and on the flash itself */
922 MTD_READOOB(thisNFTL
->mtd
, (lastEUN
* thisNFTL
->EraseSize
), 16, &retlen
,
925 oob
.u
.a
.ReplUnitNum
= oob
.u
.a
.SpareReplUnitNum
= cpu_to_le16(writeEUN
);
927 MTD_WRITEOOB(thisNFTL
->mtd
, (lastEUN
* thisNFTL
->EraseSize
), 16, &retlen
,
930 thisVUC
|= 0x8000; /* It's a replacement block */
932 /* The first block in a new chain */
933 thisNFTL
->EUNtable
[thisVUC
] = writeEUN
;
936 /* Now set up the actual EUN we're writing into */
938 /* Both in our cache... */
939 thisNFTL
->VirtualUnitTable
[writeEUN
] = thisVUC
;
940 thisNFTL
->ReplUnitTable
[writeEUN
] = 0xffff;
942 /* ... and on the flash itself */
943 MTD_READOOB(thisNFTL
->mtd
, writeEUN
* thisNFTL
->EraseSize
, 16,
944 &retlen
, (char *)&oob
);
946 oob
.u
.a
.VirtUnitNum
= oob
.u
.a
.SpareVirtUnitNum
= cpu_to_le16(thisVUC
);
948 MTD_WRITEOOB(thisNFTL
->mtd
, writeEUN
* thisNFTL
->EraseSize
, 16,
949 &retlen
, (char *)&oob
);
955 printk(KERN_WARNING
"Error folding to make room for Virtual Unit Chain 0x%x\n", thisVUC
);
959 static int NFTL_writeblock(struct NFTLrecord
*thisNFTL
, unsigned block
,
963 unsigned long blockofs
= (block
* 512) & (thisNFTL
->EraseSize
-1);
967 // if (thisEUN == 0xffff) thisEUN = 0;
969 writeEUN
= NFTL_findwriteunit(thisNFTL
, block
);
971 // printk("writeblock(%d): Write to Unit %d\n", block, writeEUN);
973 if (writeEUN
== 0xffff) {
974 printk(KERN_WARNING
"NFTL_writeblock(): Cannot find block to write to\n");
975 /* If we _still_ haven't got a block to use, we're screwed */
978 // printk("Writing block %lx to EUN %x\n",block, writeEUN);
981 thisNFTL
->mtd
->write_ecc(thisNFTL
->mtd
,
982 (writeEUN
* thisNFTL
->EraseSize
) + blockofs
,
983 512, &retlen
, (char *)buffer
, (char *)eccbuf
);
984 eccbuf
[3] = BLOCK_USED
;
985 eccbuf
[4] = eccbuf
[5] = eccbuf
[6] = eccbuf
[7] = 0xffff;
987 thisNFTL
->mtd
->write_oob(thisNFTL
->mtd
,
988 (writeEUN
* thisNFTL
->EraseSize
) + blockofs
,
989 16, &retlen
, (char *)eccbuf
);
994 #endif /* CONFIG_NFTL_RW */
996 static int NFTL_readblock(struct NFTLrecord
*thisNFTL
,
997 unsigned block
, char *buffer
)
999 u16 lastgoodEUN
= 0xffff;
1000 u16 thisEUN
= thisNFTL
->EUNtable
[block
/ (thisNFTL
->EraseSize
/ 512)];
1001 unsigned long blockofs
= (block
* 512) & (thisNFTL
->EraseSize
-1);
1005 if (thisEUN
== 0xffff) thisEUN
= 0;
1007 while(thisEUN
&& (thisEUN
& 0x7fff) != 0x7fff) {
1008 struct nftl_bci bci
;
1011 MTD_READOOB(thisNFTL
->mtd
, (thisEUN
* thisNFTL
->EraseSize
) + blockofs
,8, &retlen
, (char *)&bci
);
1013 switch(bci
.Status
) {
1014 case __constant_cpu_to_le16(BLOCK_FREE
):
1017 case __constant_cpu_to_le16(BLOCK_USED
):
1018 lastgoodEUN
= thisEUN
;
1020 case __constant_cpu_to_le16(BLOCK_IGNORE
):
1021 case __constant_cpu_to_le16(BLOCK_DELETED
):
1024 printk("Unknown status for block %d in EUN %d: %x\n",block
,thisEUN
, bci
.Status
);
1028 printk(KERN_WARNING
"Infinite loop in Virtual Unit Chain 0x%x\n",block
/ (thisNFTL
->EraseSize
/ 512));
1032 thisEUN
= thisNFTL
->ReplUnitTable
[thisEUN
] & 0x7fff;
1034 if (lastgoodEUN
== 0xffff) {
1035 memset(buffer
, 0, 512);
1037 loff_t ptr
= (lastgoodEUN
* thisNFTL
->EraseSize
) + blockofs
;
1040 thisNFTL
->mtd
->read_ecc(thisNFTL
->mtd
, ptr
, 512, &retlen
, buffer
, eccbuf
);
1046 static int nftl_ioctl(struct inode
* inode
, struct file
* file
,
1047 unsigned int cmd
, unsigned long arg
)
1049 struct NFTLrecord
*thisNFTL
;
1051 thisNFTL
= NFTLs
[MINOR(inode
->i_rdev
) / 16];
1053 if (!thisNFTL
) return -EINVAL
;
1058 struct hd_geometry g
;
1060 g
.heads
= thisNFTL
->heads
;
1061 g
.sectors
= thisNFTL
->sectors
;
1062 g
.cylinders
= thisNFTL
->cylinders
;
1063 g
.start
= part_table
[MINOR(inode
->i_rdev
)].start_sect
;
1064 return copy_to_user((void *)arg
, &g
, sizeof g
) ? -EFAULT
: 0;
1066 case BLKGETSIZE
: /* Return device size */
1067 if (!arg
) return -EINVAL
;
1068 return put_user(part_table
[MINOR(inode
->i_rdev
)].nr_sects
,
1072 if(!capable(CAP_SYS_ADMIN
)) return -EACCES
;
1073 fsync_dev(inode
->i_rdev
);
1074 invalidate_buffers(inode
->i_rdev
);
1075 if (thisNFTL
->mtd
->sync
)
1076 thisNFTL
->mtd
->sync(thisNFTL
->mtd
);
1080 if (!capable(CAP_SYS_ADMIN
)) return -EACCES
;
1081 if (thisNFTL
->usecount
> 1) {
1082 // printk("Use count %d\n", thisNFTL->usecount);
1085 #if LINUX_VERSION_CODE < 0x20328
1086 resetup_one_dev(&nftl_gendisk
, MINOR(inode
->i_dev
) / 16);
1088 grok_partitions(&nftl_gendisk
, MINOR(inode
->i_dev
) / 16, 1<<4, thisNFTL
->nr_sects
);
1092 // RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */
1099 void nftl_request(RQFUNC_ARG
)
1101 unsigned int dev
, block
, nsect
;
1102 struct NFTLrecord
*thisNFTL
;
1104 struct request
*req
;
1108 INIT_REQUEST
; /* blk.h */
1111 #ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
1112 blkdev_dequeue_request(req
);
1113 spin_unlock_irq(&io_request_lock
);
1118 DEBUG(2,"NFTL_request\n");
1119 DEBUG(3,"NFTL %d request, %lx, %lx", req
->cmd
,
1120 req
->sector
, req
->current_nr_sectors
);
1121 dev
= MINOR(req
->rq_dev
);
1122 block
= req
->sector
;
1123 nsect
= req
->current_nr_sectors
;
1124 buffer
= req
->buffer
;
1125 res
= 1; /* succeed */
1127 if (dev
>= MAX_NFTLS
* 16) {
1128 printk("fl: bad minor number: device=%s\n",
1129 kdevname(req
->rq_dev
));
1134 thisNFTL
= NFTLs
[dev
/ 16];
1135 DEBUG(3,"Waiting for mutex\n");
1136 down(&thisNFTL
->mutex
);
1137 DEBUG(3,"Got mutex\n");
1139 if (block
+ nsect
>= part_table
[dev
].nr_sects
) {
1140 printk("nftl%c%d: bad access: block=%d, count=%d\n",
1141 (MINOR(req
->rq_dev
)>>6)+'a', dev
& 0xf, block
, nsect
);
1142 up(&thisNFTL
->mutex
);
1147 block
+= part_table
[dev
].start_sect
;
1149 if (req
->cmd
== READ
) {
1150 DEBUG(2,"NFTL read\n");
1151 for ( ; nsect
> 0; nsect
-- , block
++, buffer
+= 512) {
1152 /* Read a single sector to req->buffer + (512 * i) */
1154 if (NFTL_readblock(thisNFTL
, block
, buffer
)) {
1155 DEBUG(2,"NFTL read request failed\n");
1156 up(&thisNFTL
->mutex
);
1161 DEBUG(2,"NFTL read request completed OK\n");
1162 up(&thisNFTL
->mutex
);
1165 else if (req
->cmd
== WRITE
) {
1166 DEBUG(2,"NFTL write request of 0x%x sectors @ %x (req->nr_sectors == %lx\n",nsect
, block
, req
->nr_sectors
);
1167 #ifdef CONFIG_NFTL_RW
1168 for ( ; nsect
> 0; nsect
-- , block
++, buffer
+= 512) {
1169 /* Read a single sector to req->buffer + (512 * i) */
1171 if (NFTL_writeblock(thisNFTL
, block
, buffer
)) {
1172 DEBUG(1,"NFTL write request failed\n");
1174 up(&thisNFTL
->mutex
);
1179 DEBUG(2,"NFTL write request completed OK\n");
1181 res
=0; /* Writes always fail */
1182 #endif /* CONFIG_NFTL_RW */
1183 up(&thisNFTL
->mutex
);
1187 DEBUG(0,"NFTL ??? request\n");
1188 up(&thisNFTL
->mutex
);
1193 DEBUG(3,"end_request(%d)\n", res
);
1194 #ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
1195 spin_lock_irq(&io_request_lock
);
1196 nftl_end_request(req
, res
);
1203 static int nftl_open(struct inode
*ip
, struct file
*fp
)
1205 struct NFTLrecord
*thisNFTL
;
1206 thisNFTL
= NFTLs
[MINOR(ip
->i_rdev
) / 16];
1208 DEBUG(2,"NFTL_open\n");
1211 DEBUG(2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n",
1212 MINOR(ip
->i_rdev
) / 16,ip
->i_rdev
,ip
, fp
);
1215 #ifndef CONFIG_NFTL_RW
1216 if (fp
->f_mode
& FMODE_WRITE
)
1218 #endif /* !CONFIG_NFTL_RW */
1219 thisNFTL
->usecount
++;
1221 if (!get_mtd_device(thisNFTL
->mtd
, -1)) {
1223 return /* -E'SBUGGEREDOFF */ -ENXIO
;
1229 static int nftl_release(struct inode
*inode
, struct file
*fp
)
1231 struct super_block
*sb
= get_super(inode
->i_rdev
);
1232 struct NFTLrecord
*thisNFTL
;
1234 thisNFTL
= NFTLs
[MINOR(inode
->i_rdev
) / 16];
1236 DEBUG(2, "NFTL_release\n");
1238 fsync_dev(inode
->i_rdev
);
1240 invalidate_inodes(sb
);
1241 invalidate_buffers(inode
->i_rdev
);
1243 if (thisNFTL
->mtd
->sync
)
1244 thisNFTL
->mtd
->sync(thisNFTL
->mtd
);
1245 thisNFTL
->usecount
--;
1248 put_mtd_device(thisNFTL
->mtd
);
1252 #if LINUX_VERSION_CODE < 0x20326
1253 static struct file_operations nftl_fops
= {
1254 NULL
, /* lseek - default */
1255 block_read
, /* read - block dev read */
1256 block_write
, /* write - block dev write */
1257 NULL
, /* readdir - not here! */
1259 nftl_ioctl
, /* ioctl */
1261 nftl_open
, /* open */
1263 nftl_release
, /* no special release code... */
1264 block_fsync
/* fsync */
1267 static struct block_device_operations nftl_fops
=
1270 release
: nftl_release
,
1277 /****************************************************************************
1281 ****************************************************************************/
1283 #if LINUX_VERSION_CODE < 0x20300
1285 #define init_nftl init_module
1286 #define cleanup_nftl cleanup_module
1291 static struct mtd_notifier nftl_notifier
= {NFTL_notify_add
, NFTL_notify_remove
, NULL
};
1294 /* static int __init init_nftl(void) */
1295 int __init
init_nftl(void)
1299 printk(KERN_NOTICE
"M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");
1301 printk(KERN_INFO
"$Id: nftl.c,v 1.35 2000/07/06 14:35:01 dwmw2 Exp $\n");
1304 if (register_blkdev(NFTL_MAJOR
, "nftl", &nftl_fops
)){
1305 printk("unable to register NFTL block device\n");
1307 #if LINUX_VERSION_CODE < 0x20320
1308 blk_dev
[MAJOR_NR
].request_fn
= nftl_request
;
1310 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), &nftl_request
);
1312 for (i
=0; i
< 256 ; i
++) {
1313 nftl_blocksizes
[i
] = 1024;
1315 blksize_size
[NFTL_MAJOR
] = nftl_blocksizes
;
1316 nftl_gendisk
.next
= gendisk_head
;
1317 gendisk_head
= &nftl_gendisk
;
1320 register_mtd_user(&nftl_notifier
);
1325 static void __exit
cleanup_nftl(void)
1327 struct gendisk
*gd
, **gdp
;
1329 unregister_mtd_user(&nftl_notifier
);
1331 unregister_blkdev(NFTL_MAJOR
, "nftl");
1332 #if LINUX_VERSION_CODE < 0x20320
1333 blk_dev
[MAJOR_NR
].request_fn
= 0;
1335 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
1337 for (gdp
= &gendisk_head
; *gdp
; gdp
= &((*gdp
)->next
))
1338 if (*gdp
== &nftl_gendisk
) {
1339 gd
= *gdp
; *gdp
= gd
->next
;
1345 #if LINUX_VERSION_CODE > 0x20300
1346 module_init(init_nftl
);
1347 module_exit(cleanup_nftl
);