File: /usr/src/linux/drivers/mtd/nftlcore.c
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.73 2001/06/09 01:09:43 dwmw2 Exp $ */
5
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.
10 */
11
12 #define PRERELEASE
13
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
28 #ifdef CONFIG_KMOD
29 #include <linux/kmod.h>
30 #endif
31 #include <linux/mtd/mtd.h>
32 #include <linux/mtd/nftl.h>
33 #include <linux/mtd/compatmac.h>
34
35 /* maximum number of loops while examining next block, to have a
36 chance to detect consistency problems (they should never happen
37 because of the checks done in the mounting */
38
39 #define MAX_LOOPS 10000
40
41 /* NFTL block device stuff */
42 #define MAJOR_NR NFTL_MAJOR
43 #define DEVICE_REQUEST nftl_request
44 #define DEVICE_OFF(device)
45
46
47 #include <linux/blk.h>
48 #include <linux/hdreg.h>
49
50 /* Linux-specific block device functions */
51
52 /* I _HATE_ the Linux block device setup more than anything else I've ever
53 * encountered, except ...
54 */
55
56 static int nftl_sizes[256];
57 static int nftl_blocksizes[256];
58
59 /* .. for the Linux partition table handling. */
60 struct hd_struct part_table[256];
61
62 #if LINUX_VERSION_CODE < 0x20328
63 static void dummy_init (struct gendisk *crap)
64 {}
65 #endif
66
67 static struct gendisk nftl_gendisk = {
68 major: MAJOR_NR,
69 major_name: "nftl",
70 minor_shift: NFTL_PARTN_BITS, /* Bits to shift to get real from partition */
71 max_p: (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */
72 #if LINUX_VERSION_CODE < 0x20328
73 max_nr: MAX_NFTLS, /* maximum number of real */
74 init: dummy_init, /* init function */
75 #endif
76 part: part_table, /* hd struct */
77 sizes: nftl_sizes, /* block sizes */
78 };
79
80 struct NFTLrecord *NFTLs[MAX_NFTLS];
81
82 static void NFTL_setup(struct mtd_info *mtd)
83 {
84 int i;
85 struct NFTLrecord *nftl;
86 unsigned long temp;
87 int firstfree = -1;
88
89 DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
90
91 for (i = 0; i < MAX_NFTLS; i++) {
92 if (!NFTLs[i] && firstfree == -1)
93 firstfree = i;
94 else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
95 /* This is a Spare Media Header for an NFTL we've already found */
96 DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
97 return;
98 }
99 }
100 if (firstfree == -1) {
101 printk(KERN_WARNING "No more NFTL slot available\n");
102 return;
103 }
104
105 nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
106 if (!nftl) {
107 printk(KERN_WARNING "Out of memory for NFTL data structures\n");
108 return;
109 }
110
111 init_MUTEX(&nftl->mutex);
112
113 /* get physical parameters */
114 nftl->EraseSize = mtd->erasesize;
115 nftl->nb_blocks = mtd->size / mtd->erasesize;
116 nftl->mtd = mtd;
117
118 if (NFTL_mount(nftl) < 0) {
119 printk(KERN_WARNING "Could not mount NFTL device\n");
120 kfree(nftl);
121 return;
122 }
123
124 /* OK, it's a new one. Set up all the data structures. */
125 #ifdef PSYCHO_DEBUG
126 printk("Found new NFTL nftl%c\n", firstfree + 'a');
127 #endif
128
129 /* linux stuff */
130 nftl->usecount = 0;
131 nftl->cylinders = 1024;
132 nftl->heads = 16;
133
134 temp = nftl->cylinders * nftl->heads;
135 nftl->sectors = nftl->nr_sects / temp;
136 if (nftl->nr_sects % temp) {
137 nftl->sectors++;
138 temp = nftl->cylinders * nftl->sectors;
139 nftl->heads = nftl->nr_sects / temp;
140
141 if (nftl->nr_sects % temp) {
142 nftl->heads++;
143 temp = nftl->heads * nftl->sectors;
144 nftl->cylinders = nftl->nr_sects / temp;
145 }
146 }
147
148 if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
149 printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
150 "match size of 0x%lx.\n", nftl->nr_sects);
151 printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n",
152 nftl->cylinders, nftl->heads , nftl->sectors,
153 (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
154
155 /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
156 }
157 NFTLs[firstfree] = nftl;
158 /* Finally, set up the block device sizes */
159 nftl_sizes[firstfree * 16] = nftl->nr_sects;
160 //nftl_blocksizes[firstfree*16] = 512;
161 part_table[firstfree * 16].nr_sects = nftl->nr_sects;
162
163 nftl_gendisk.nr_real++;
164
165 /* partition check ... */
166 #if LINUX_VERSION_CODE < 0x20328
167 resetup_one_dev(&nftl_gendisk, firstfree);
168 #else
169 grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects);
170 #endif
171 }
172
173 static void NFTL_unsetup(int i)
174 {
175 struct NFTLrecord *nftl = NFTLs[i];
176
177 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
178
179 NFTLs[i] = NULL;
180
181 if (nftl->ReplUnitTable)
182 kfree(nftl->ReplUnitTable);
183 if (nftl->EUNtable)
184 kfree(nftl->EUNtable);
185
186 nftl_gendisk.nr_real--;
187 kfree(nftl);
188 }
189
190 /* Search the MTD device for NFTL partitions */
191 static void NFTL_notify_add(struct mtd_info *mtd)
192 {
193 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
194
195 if (mtd) {
196 if (!mtd->read_oob) {
197 /* If this MTD doesn't have out-of-band data,
198 then there's no point continuing */
199 DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
200 return;
201 }
202 DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n",
203 mtd->read, mtd->size, mtd->erasesize);
204
205 NFTL_setup(mtd);
206 }
207 }
208
209 static void NFTL_notify_remove(struct mtd_info *mtd)
210 {
211 int i;
212
213 for (i = 0; i < MAX_NFTLS; i++) {
214 if (NFTLs[i] && NFTLs[i]->mtd == mtd)
215 NFTL_unsetup(i);
216 }
217 }
218
219 #ifdef CONFIG_NFTL_RW
220
221 /* Actual NFTL access routines */
222 /* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
223 * when the give Virtual Unit Chain
224 */
225 static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
226 {
227 /* For a given Virtual Unit Chain: find or create a free block and
228 add it to the chain */
229 /* We're passed the number of the last EUN in the chain, to save us from
230 having to look it up again */
231 u16 pot = nftl->LastFreeEUN;
232 int silly = -1;
233
234 /* Normally, we force a fold to happen before we run out of free blocks completely */
235 if (!desperate && nftl->numfreeEUNs < 2) {
236 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
237 return 0xffff;
238 }
239
240 /* Scan for a free block */
241 do {
242 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
243 nftl->LastFreeEUN = pot;
244 nftl->numfreeEUNs--;
245 return pot;
246 }
247
248 /* This will probably point to the MediaHdr unit itself,
249 right at the beginning of the partition. But that unit
250 (and the backup unit too) should have the UCI set
251 up so that it's not selected for overwriting */
252 if (++pot > nftl->lastEUN)
253 pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
254
255 if (!silly--) {
256 printk("Argh! No free blocks found! LastFreeEUN = %d, "
257 "FirstEUN = %d\n", nftl->LastFreeEUN,
258 le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
259 return 0xffff;
260 }
261 } while (pot != nftl->LastFreeEUN);
262
263 return 0xffff;
264 }
265
266 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
267 {
268 u16 BlockMap[MAX_SECTORS_PER_UNIT];
269 unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
270 unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
271 unsigned int thisEUN;
272 int block;
273 int silly;
274 unsigned int targetEUN;
275 struct nftl_oob oob;
276 int inplace = 1;
277 size_t retlen;
278
279 memset(BlockMap, 0xff, sizeof(BlockMap));
280 memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
281
282 thisEUN = nftl->EUNtable[thisVUC];
283
284 if (thisEUN == BLOCK_NIL) {
285 printk(KERN_WARNING "Trying to fold non-existent "
286 "Virtual Unit Chain %d!\n", thisVUC);
287 return BLOCK_NIL;
288 }
289
290 /* Scan to find the Erase Unit which holds the actual data for each
291 512-byte block within the Chain.
292 */
293 silly = MAX_LOOPS;
294 targetEUN = BLOCK_NIL;
295 while (thisEUN <= nftl->lastEUN ) {
296 unsigned int status, foldmark;
297
298 targetEUN = thisEUN;
299 for (block = 0; block < nftl->EraseSize / 512; block ++) {
300 MTD_READOOB(nftl->mtd,
301 (thisEUN * nftl->EraseSize) + (block * 512),
302 16 , &retlen, (char *)&oob);
303 if (block == 2) {
304 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
305 if (foldmark == FOLD_MARK_IN_PROGRESS) {
306 DEBUG(MTD_DEBUG_LEVEL1,
307 "Write Inhibited on EUN %d\n", thisEUN);
308 inplace = 0;
309 } else {
310 /* There's no other reason not to do inplace,
311 except ones that come later. So we don't need
312 to preserve inplace */
313 inplace = 1;
314 }
315 }
316 status = oob.b.Status | oob.b.Status1;
317 BlockLastState[block] = status;
318
319 switch(status) {
320 case SECTOR_FREE:
321 BlockFreeFound[block] = 1;
322 break;
323
324 case SECTOR_USED:
325 if (!BlockFreeFound[block])
326 BlockMap[block] = thisEUN;
327 else
328 printk(KERN_WARNING
329 "SECTOR_USED found after SECTOR_FREE "
330 "in Virtual Unit Chain %d for block %d\n",
331 thisVUC, block);
332 break;
333 case SECTOR_IGNORE:
334 case SECTOR_DELETED:
335 break;
336 default:
337 printk("Unknown status for block %d in EUN %d: %x\n",
338 block, thisEUN, status);
339 }
340 }
341
342 if (!silly--) {
343 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
344 thisVUC);
345 return BLOCK_NIL;
346 }
347
348 thisEUN = nftl->ReplUnitTable[thisEUN];
349 }
350
351 if (inplace) {
352 /* We're being asked to be a fold-in-place. Check
353 that all blocks are either present or SECTOR_FREE
354 in the target block. If not, we're going to have
355 to fold out-of-place anyway.
356 */
357 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
358 if (BlockLastState[block] != SECTOR_FREE &&
359 BlockMap[block] != targetEUN) {
360 DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
361 "block %d was %x lastEUN, "
362 "and is in EUN %d (%s) %d\n",
363 thisVUC, block, BlockLastState[block],
364 BlockMap[block],
365 BlockMap[block]== targetEUN ? "==" : "!=",
366 targetEUN);
367 inplace = 0;
368 break;
369 }
370 }
371
372 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
373 pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
374 BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
375 SECTOR_FREE) {
376 DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
377 "Folding out of place.\n", targetEUN);
378 inplace = 0;
379 }
380 }
381
382 if (!inplace) {
383 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
384 "Trying out-of-place\n", thisVUC);
385 /* We need to find a targetEUN to fold into. */
386 targetEUN = NFTL_findfreeblock(nftl, 1);
387 if (targetEUN == BLOCK_NIL) {
388 /* Ouch. Now we're screwed. We need to do a
389 fold-in-place of another chain to make room
390 for this one. We need a better way of selecting
391 which chain to fold, because makefreeblock will
392 only ask us to fold the same one again.
393 */
394 printk(KERN_WARNING
395 "NFTL_findfreeblock(desperate) returns 0xffff.\n");
396 return BLOCK_NIL;
397 }
398 } else {
399 /* We put a fold mark in the chain we are folding only if
400 we fold in place to help the mount check code. If we do
401 not fold in place, it is possible to find the valid
402 chain by selecting the longer one */
403 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
404 oob.u.c.unused = 0xffffffff;
405 MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
406 8, &retlen, (char *)&oob.u);
407 }
408
409 /* OK. We now know the location of every block in the Virtual Unit Chain,
410 and the Erase Unit into which we are supposed to be copying.
411 Go for it.
412 */
413 DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
414 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
415 unsigned char movebuf[512];
416 int ret;
417
418 /* If it's in the target EUN already, or if it's pending write, do nothing */
419 if (BlockMap[block] == targetEUN ||
420 (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
421 continue;
422 }
423
424 /* copy only in non free block (free blocks can only
425 happen in case of media errors or deleted blocks) */
426 if (BlockMap[block] == BLOCK_NIL)
427 continue;
428
429 ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
430 + (block * 512), 512, &retlen, movebuf, (char *)&oob);
431 if (ret < 0) {
432 ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
433 + (block * 512), 512, &retlen,
434 movebuf, (char *)&oob);
435 if (ret != -EIO)
436 printk("Error went away on retry.\n");
437 }
438 MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
439 512, &retlen, movebuf, (char *)&oob);
440 }
441
442 /* add the header so that it is now a valid chain */
443 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
444 = cpu_to_le16(thisVUC);
445 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
446
447 MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8,
448 8, &retlen, (char *)&oob.u);
449
450 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
451
452 /* At this point, we have two different chains for this Virtual Unit, and no way to tell
453 them apart. If we crash now, we get confused. However, both contain the same data, so we
454 shouldn't actually lose data in this case. It's just that when we load up on a medium which
455 has duplicate chains, we need to free one of the chains because it's not necessary any more.
456 */
457 thisEUN = nftl->EUNtable[thisVUC];
458 DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
459
460 /* For each block in the old chain (except the targetEUN of course),
461 free it and make it available for future use */
462 while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
463 unsigned int EUNtmp;
464
465 EUNtmp = nftl->ReplUnitTable[thisEUN];
466
467 if (NFTL_formatblock(nftl, thisEUN) < 0) {
468 /* could not erase : mark block as reserved
469 * FixMe: Update Bad Unit Table on disk
470 */
471 nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
472 } else {
473 /* correctly erased : mark it as free */
474 nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
475 nftl->numfreeEUNs++;
476 }
477 thisEUN = EUNtmp;
478 }
479
480 /* Make this the new start of chain for thisVUC */
481 nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
482 nftl->EUNtable[thisVUC] = targetEUN;
483
484 return targetEUN;
485 }
486
487 u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
488 {
489 /* This is the part that needs some cleverness applied.
490 For now, I'm doing the minimum applicable to actually
491 get the thing to work.
492 Wear-levelling and other clever stuff needs to be implemented
493 and we also need to do some assessment of the results when
494 the system loses power half-way through the routine.
495 */
496 u16 LongestChain = 0;
497 u16 ChainLength = 0, thislen;
498 u16 chain, EUN;
499
500 for (chain = 0; chain < nftl->MediaHdr.FormattedSize / nftl->EraseSize; chain++) {
501 EUN = nftl->EUNtable[chain];
502 thislen = 0;
503
504 while (EUN <= nftl->lastEUN) {
505 thislen++;
506 //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
507 EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
508 if (thislen > 0xff00) {
509 printk("Endless loop in Virtual Chain %d: Unit %x\n",
510 chain, EUN);
511 }
512 if (thislen > 0xff10) {
513 /* Actually, don't return failure. Just ignore this chain and
514 get on with it. */
515 thislen = 0;
516 break;
517 }
518 }
519
520 if (thislen > ChainLength) {
521 //printk("New longest chain is %d with length %d\n", chain, thislen);
522 ChainLength = thislen;
523 LongestChain = chain;
524 }
525 }
526
527 if (ChainLength < 2) {
528 printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
529 "Failing request\n");
530 return 0xffff;
531 }
532
533 return NFTL_foldchain (nftl, LongestChain, pendingblock);
534 }
535
536 /* NFTL_findwriteunit: Return the unit number into which we can write
537 for this block. Make it available if it isn't already
538 */
539 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
540 {
541 u16 lastEUN;
542 u16 thisVUC = block / (nftl->EraseSize / 512);
543 unsigned int writeEUN;
544 unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
545 size_t retlen;
546 int silly, silly2 = 3;
547 struct nftl_oob oob;
548
549 do {
550 /* Scan the media to find a unit in the VUC which has
551 a free space for the block in question.
552 */
553
554 /* This condition catches the 0x[7f]fff cases, as well as
555 being a sanity check for past-end-of-media access
556 */
557 lastEUN = BLOCK_NIL;
558 writeEUN = nftl->EUNtable[thisVUC];
559 silly = MAX_LOOPS;
560 while (writeEUN <= nftl->lastEUN) {
561 struct nftl_bci bci;
562 size_t retlen;
563 unsigned int status;
564
565 lastEUN = writeEUN;
566
567 MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
568 8, &retlen, (char *)&bci);
569
570 DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
571 block , writeEUN, le16_to_cpu(bci.Status));
572
573 status = bci.Status | bci.Status1;
574 switch(status) {
575 case SECTOR_FREE:
576 return writeEUN;
577
578 case SECTOR_DELETED:
579 case SECTOR_USED:
580 case SECTOR_IGNORE:
581 break;
582 default:
583 // Invalid block. Don't use it any more. Must implement.
584 break;
585 }
586
587 if (!silly--) {
588 printk(KERN_WARNING
589 "Infinite loop in Virtual Unit Chain 0x%x\n",
590 thisVUC);
591 return 0xffff;
592 }
593
594 /* Skip to next block in chain */
595 writeEUN = nftl->ReplUnitTable[writeEUN];
596 }
597
598 /* OK. We didn't find one in the existing chain, or there
599 is no existing chain. */
600
601 /* Try to find an already-free block */
602 writeEUN = NFTL_findfreeblock(nftl, 0);
603
604 if (writeEUN == BLOCK_NIL) {
605 /* That didn't work - there were no free blocks just
606 waiting to be picked up. We're going to have to fold
607 a chain to make room.
608 */
609
610 /* First remember the start of this chain */
611 //u16 startEUN = nftl->EUNtable[thisVUC];
612
613 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
614 writeEUN = NFTL_makefreeblock(nftl, 0xffff);
615
616 if (writeEUN == BLOCK_NIL) {
617 /* OK, we accept that the above comment is
618 lying - there may have been free blocks
619 last time we called NFTL_findfreeblock(),
620 but they are reserved for when we're
621 desperate. Well, now we're desperate.
622 */
623 DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
624 writeEUN = NFTL_findfreeblock(nftl, 1);
625 }
626 if (writeEUN == BLOCK_NIL) {
627 /* Ouch. This should never happen - we should
628 always be able to make some room somehow.
629 If we get here, we've allocated more storage
630 space than actual media, or our makefreeblock
631 routine is missing something.
632 */
633 printk(KERN_WARNING "Cannot make free space.\n");
634 return BLOCK_NIL;
635 }
636 //printk("Restarting scan\n");
637 lastEUN = BLOCK_NIL;
638 continue;
639 }
640
641 /* We've found a free block. Insert it into the chain. */
642
643 if (lastEUN != BLOCK_NIL) {
644 thisVUC |= 0x8000; /* It's a replacement block */
645 } else {
646 /* The first block in a new chain */
647 nftl->EUNtable[thisVUC] = writeEUN;
648 }
649
650 /* set up the actual EUN we're writing into */
651 /* Both in our cache... */
652 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
653
654 /* ... and on the flash itself */
655 MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
656 &retlen, (char *)&oob.u);
657
658 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
659
660 MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
661 &retlen, (char *)&oob.u);
662
663 /* we link the new block to the chain only after the
664 block is ready. It avoids the case where the chain
665 could point to a free block */
666 if (lastEUN != BLOCK_NIL) {
667 /* Both in our cache... */
668 nftl->ReplUnitTable[lastEUN] = writeEUN;
669 /* ... and on the flash itself */
670 MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
671 8, &retlen, (char *)&oob.u);
672
673 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
674 = cpu_to_le16(writeEUN);
675
676 MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
677 8, &retlen, (char *)&oob.u);
678 }
679
680 return writeEUN;
681
682 } while (silly2--);
683
684 printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
685 thisVUC);
686 return 0xffff;
687 }
688
689 static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
690 {
691 u16 writeEUN;
692 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
693 size_t retlen;
694 u8 eccbuf[6];
695
696 writeEUN = NFTL_findwriteunit(nftl, block);
697
698 if (writeEUN == BLOCK_NIL) {
699 printk(KERN_WARNING
700 "NFTL_writeblock(): Cannot find block to write to\n");
701 /* If we _still_ haven't got a block to use, we're screwed */
702 return 1;
703 }
704
705 MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
706 512, &retlen, (char *)buffer, (char *)eccbuf);
707 /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
708
709 return 0;
710 }
711 #endif /* CONFIG_NFTL_RW */
712
713 static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
714 {
715 u16 lastgoodEUN;
716 u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
717 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
718 unsigned int status;
719 int silly = MAX_LOOPS;
720 size_t retlen;
721 struct nftl_bci bci;
722
723 lastgoodEUN = BLOCK_NIL;
724
725 if (thisEUN != BLOCK_NIL) {
726 while (thisEUN < nftl->nb_blocks) {
727 if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
728 8, &retlen, (char *)&bci) < 0)
729 status = SECTOR_IGNORE;
730 else
731 status = bci.Status | bci.Status1;
732
733 switch (status) {
734 case SECTOR_FREE:
735 /* no modification of a sector should follow a free sector */
736 goto the_end;
737 case SECTOR_DELETED:
738 lastgoodEUN = BLOCK_NIL;
739 break;
740 case SECTOR_USED:
741 lastgoodEUN = thisEUN;
742 break;
743 case SECTOR_IGNORE:
744 break;
745 default:
746 printk("Unknown status for block %d in EUN %d: %x\n",
747 block, thisEUN, status);
748 break;
749 }
750
751 if (!silly--) {
752 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
753 block / (nftl->EraseSize / 512));
754 return 1;
755 }
756 thisEUN = nftl->ReplUnitTable[thisEUN];
757 }
758 }
759
760 the_end:
761 if (lastgoodEUN == BLOCK_NIL) {
762 /* the requested block is not on the media, return all 0x00 */
763 memset(buffer, 0, 512);
764 } else {
765 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
766 size_t retlen;
767 u_char eccbuf[6];
768 if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf))
769 return -EIO;
770 }
771 return 0;
772 }
773
774 static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
775 {
776 struct NFTLrecord *nftl;
777 int p;
778
779 nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS];
780
781 if (!nftl) return -EINVAL;
782
783 switch (cmd) {
784 case HDIO_GETGEO: {
785 struct hd_geometry g;
786
787 g.heads = nftl->heads;
788 g.sectors = nftl->sectors;
789 g.cylinders = nftl->cylinders;
790 g.start = part_table[MINOR(inode->i_rdev)].start_sect;
791 return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
792 }
793 case BLKGETSIZE: /* Return device size */
794 return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
795 (long *) arg);
796 case BLKGETSIZE64:
797 return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
798 (u64 *)arg);
799
800 case BLKFLSBUF:
801 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
802 fsync_dev(inode->i_rdev);
803 invalidate_buffers(inode->i_rdev);
804 if (nftl->mtd->sync)
805 nftl->mtd->sync(nftl->mtd);
806 return 0;
807
808 case BLKRRPART:
809 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
810 if (nftl->usecount > 1) return -EBUSY;
811 /*
812 * We have to flush all buffers and invalidate caches,
813 * or we won't be able to re-use the partitions,
814 * if there was a change and we don't want to reboot
815 */
816 p = (1<<NFTL_PARTN_BITS) - 1;
817 while (p-- > 0) {
818 kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p);
819 if (part_table[p].nr_sects > 0)
820 invalidate_device (devp, 1);
821
822 part_table[MINOR(inode->i_dev)+p].start_sect = 0;
823 part_table[MINOR(inode->i_dev)+p].nr_sects = 0;
824 }
825
826 #if LINUX_VERSION_CODE < 0x20328
827 resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS);
828 #else
829 grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS,
830 1<<NFTL_PARTN_BITS, nftl->nr_sects);
831 #endif
832 return 0;
833
834 #if (LINUX_VERSION_CODE < 0x20303)
835 RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */
836 #else
837 case BLKROSET:
838 case BLKROGET:
839 case BLKSSZGET:
840 return blk_ioctl(inode->i_rdev, cmd, arg);
841 #endif
842
843 default:
844 return -EINVAL;
845 }
846 }
847
848 void nftl_request(RQFUNC_ARG)
849 {
850 unsigned int dev, block, nsect;
851 struct NFTLrecord *nftl;
852 char *buffer;
853 struct request *req;
854 int res;
855
856 while (1) {
857 INIT_REQUEST; /* blk.h */
858 req = CURRENT;
859
860 /* We can do this because the generic code knows not to
861 touch the request at the head of the queue */
862 spin_unlock_irq(&io_request_lock);
863
864 DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
865 DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
866 (req->cmd == READ) ? "Read " : "Write",
867 req->sector, req->current_nr_sectors);
868
869 dev = MINOR(req->rq_dev);
870 block = req->sector;
871 nsect = req->current_nr_sectors;
872 buffer = req->buffer;
873 res = 1; /* succeed */
874
875 if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) {
876 /* there is no such partition */
877 printk("nftl: bad minor number: device = %s\n",
878 kdevname(req->rq_dev));
879 res = 0; /* fail */
880 goto repeat;
881 }
882
883 nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)];
884 DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
885 down(&nftl->mutex);
886 DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
887
888 if (block + nsect > part_table[dev].nr_sects) {
889 /* access past the end of device */
890 printk("nftl%c%d: bad access: block = %d, count = %d\n",
891 (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
892 up(&nftl->mutex);
893 res = 0; /* fail */
894 goto repeat;
895 }
896
897 block += part_table[dev].start_sect;
898
899 if (req->cmd == READ) {
900 DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
901 "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
902
903 for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
904 /* Read a single sector to req->buffer + (512 * i) */
905 if (NFTL_readblock(nftl, block, buffer)) {
906 DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
907 up(&nftl->mutex);
908 res = 0;
909 goto repeat;
910 }
911 }
912
913 DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
914 up(&nftl->mutex);
915 goto repeat;
916 } else if (req->cmd == WRITE) {
917 DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
918 "(req->nr_sectors == %lx)\n", nsect, block,
919 req->nr_sectors);
920 #ifdef CONFIG_NFTL_RW
921 for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
922 /* Read a single sector to req->buffer + (512 * i) */
923 if (NFTL_writeblock(nftl, block, buffer)) {
924 DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
925 up(&nftl->mutex);
926 res = 0;
927 goto repeat;
928 }
929 }
930 DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
931 #else
932 res = 0; /* Writes always fail */
933 #endif /* CONFIG_NFTL_RW */
934 up(&nftl->mutex);
935 goto repeat;
936 } else {
937 DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
938 up(&nftl->mutex);
939 res = 0;
940 goto repeat;
941 }
942 repeat:
943 DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
944 spin_lock_irq(&io_request_lock);
945 end_request(res);
946 }
947 }
948
949 static int nftl_open(struct inode *ip, struct file *fp)
950 {
951 int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS;
952 struct NFTLrecord *thisNFTL;
953 thisNFTL = NFTLs[nftlnum];
954
955 DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
956
957 #ifdef CONFIG_KMOD
958 if (!thisNFTL && nftlnum == 0) {
959 request_module("docprobe");
960 thisNFTL = NFTLs[nftlnum];
961 }
962 #endif
963 if (!thisNFTL) {
964 DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n",
965 nftlnum, ip->i_rdev, ip, fp);
966 return -ENODEV;
967 }
968
969 #ifndef CONFIG_NFTL_RW
970 if (fp->f_mode & FMODE_WRITE)
971 return -EROFS;
972 #endif /* !CONFIG_NFTL_RW */
973
974 thisNFTL->usecount++;
975 MOD_INC_USE_COUNT;
976 if (!get_mtd_device(thisNFTL->mtd, -1)) {
977 MOD_DEC_USE_COUNT;
978 return /* -E'SBUGGEREDOFF */ -ENXIO;
979 }
980
981 return 0;
982 }
983
984 static int nftl_release(struct inode *inode, struct file *fp)
985 {
986 struct NFTLrecord *thisNFTL;
987
988 thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
989
990 DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
991
992 invalidate_device(inode->i_rdev, 1);
993
994 if (thisNFTL->mtd->sync)
995 thisNFTL->mtd->sync(thisNFTL->mtd);
996 thisNFTL->usecount--;
997 MOD_DEC_USE_COUNT;
998
999 put_mtd_device(thisNFTL->mtd);
1000
1001 return 0;
1002 }
1003 #if LINUX_VERSION_CODE < 0x20326
1004 static struct file_operations nftl_fops = {
1005 read: block_read,
1006 write: block_write,
1007 ioctl: nftl_ioctl,
1008 open: nftl_open,
1009 release: nftl_release,
1010 fsync: block_fsync,
1011 };
1012 #else
1013 static struct block_device_operations nftl_fops =
1014 {
1015 open: nftl_open,
1016 release: nftl_release,
1017 ioctl: nftl_ioctl
1018 };
1019 #endif
1020
1021
1022
1023 /****************************************************************************
1024 *
1025 * Module stuff
1026 *
1027 ****************************************************************************/
1028
1029 static struct mtd_notifier nftl_notifier = {
1030 add: NFTL_notify_add,
1031 remove: NFTL_notify_remove
1032 };
1033
1034 static int __init init_nftl(void)
1035 {
1036 int i;
1037
1038 printk(KERN_NOTICE
1039 "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");
1040 #ifdef PRERELEASE
1041 printk(KERN_INFO"$Id: nftlcore.c,v 1.73 2001/06/09 01:09:43 dwmw2 Exp $\n");
1042 #endif
1043
1044 if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
1045 printk("unable to register NFTL block device on major %d\n",
1046 MAJOR_NR);
1047 return -EBUSY;
1048 } else {
1049 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
1050
1051 /* set block size to 1kB each */
1052 for (i = 0; i < 256; i++) {
1053 nftl_blocksizes[i] = 1024;
1054 }
1055 blksize_size[MAJOR_NR] = nftl_blocksizes;
1056
1057 add_gendisk(&nftl_gendisk);
1058 }
1059
1060 register_mtd_user(&nftl_notifier);
1061
1062 return 0;
1063 }
1064
1065 static void __exit cleanup_nftl(void)
1066 {
1067 unregister_mtd_user(&nftl_notifier);
1068 unregister_blkdev(MAJOR_NR, "nftl");
1069
1070 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1071
1072 del_gendisk(&nftl_gendisk);
1073 }
1074
1075 module_init(init_nftl);
1076 module_exit(cleanup_nftl);
1077