]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/mtd/nftlcore.c
[MTD] Allow variable block sizes in mtd_blkdevs
[net-next-2.6.git] / drivers / mtd / nftlcore.c
CommitLineData
1da177e4
LT
1/* Linux driver for NAND Flash Translation Layer */
2/* (c) 1999 Machine Vision Holdings, Inc. */
3/* Author: David Woodhouse <dwmw2@infradead.org> */
97894cda 4/* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */
1da177e4
LT
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
1da177e4
LT
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <asm/errno.h>
17#include <asm/io.h>
18#include <asm/uaccess.h>
19#include <linux/miscdevice.h>
20#include <linux/pci.h>
21#include <linux/delay.h>
22#include <linux/slab.h>
23#include <linux/sched.h>
24#include <linux/init.h>
25#include <linux/hdreg.h>
26
27#include <linux/kmod.h>
28#include <linux/mtd/mtd.h>
29#include <linux/mtd/nand.h>
30#include <linux/mtd/nftl.h>
31#include <linux/mtd/blktrans.h>
32
33/* maximum number of loops while examining next block, to have a
34 chance to detect consistency problems (they should never happen
35 because of the checks done in the mounting */
36
37#define MAX_LOOPS 10000
38
39
40static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
41{
42 struct NFTLrecord *nftl;
43 unsigned long temp;
44
45 if (mtd->type != MTD_NANDFLASH)
46 return;
47 /* OK, this is moderately ugly. But probably safe. Alternatives? */
48 if (memcmp(mtd->name, "DiskOnChip", 10))
49 return;
50
51 if (!mtd->block_isbad) {
52 printk(KERN_ERR
53"NFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
54"Please use the new diskonchip driver under the NAND subsystem.\n");
55 return;
56 }
57
58 DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
59
60 nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
61
62 if (!nftl) {
63 printk(KERN_WARNING "NFTL: out of memory for data structures\n");
64 return;
65 }
66 memset(nftl, 0, sizeof(*nftl));
67
68 nftl->mbd.mtd = mtd;
69 nftl->mbd.devnum = -1;
19187672 70
1da177e4 71 nftl->mbd.tr = tr;
1da177e4
LT
72
73 if (NFTL_mount(nftl) < 0) {
74 printk(KERN_WARNING "NFTL: could not mount device\n");
75 kfree(nftl);
76 return;
77 }
78
79 /* OK, it's a new one. Set up all the data structures. */
80
81 /* Calculate geometry */
82 nftl->cylinders = 1024;
83 nftl->heads = 16;
84
85 temp = nftl->cylinders * nftl->heads;
86 nftl->sectors = nftl->mbd.size / temp;
87 if (nftl->mbd.size % temp) {
88 nftl->sectors++;
89 temp = nftl->cylinders * nftl->sectors;
90 nftl->heads = nftl->mbd.size / temp;
91
92 if (nftl->mbd.size % temp) {
93 nftl->heads++;
94 temp = nftl->heads * nftl->sectors;
95 nftl->cylinders = nftl->mbd.size / temp;
96 }
97 }
98
99 if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
100 /*
97894cda 101 Oh no we don't have
1da177e4
LT
102 mbd.size == heads * cylinders * sectors
103 */
104 printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
105 "match size of 0x%lx.\n", nftl->mbd.size);
106 printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
107 "(== 0x%lx sects)\n",
97894cda 108 nftl->cylinders, nftl->heads , nftl->sectors,
1da177e4
LT
109 (long)nftl->cylinders * (long)nftl->heads *
110 (long)nftl->sectors );
111 }
112
113 if (add_mtd_blktrans_dev(&nftl->mbd)) {
fa671646
JJ
114 kfree(nftl->ReplUnitTable);
115 kfree(nftl->EUNtable);
1da177e4
LT
116 kfree(nftl);
117 return;
118 }
119#ifdef PSYCHO_DEBUG
120 printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
121#endif
122}
123
124static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
125{
126 struct NFTLrecord *nftl = (void *)dev;
127
128 DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
129
130 del_mtd_blktrans_dev(dev);
fa671646
JJ
131 kfree(nftl->ReplUnitTable);
132 kfree(nftl->EUNtable);
1da177e4
LT
133 kfree(nftl);
134}
135
8593fbc6
TG
136/*
137 * Read oob data from flash
138 */
139int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
140 size_t *retlen, uint8_t *buf)
141{
142 struct mtd_oob_ops ops;
143 int res;
144
145 ops.mode = MTD_OOB_PLACE;
146 ops.ooboffs = offs & (mtd->writesize - 1);
147 ops.ooblen = len;
148 ops.oobbuf = buf;
149 ops.datbuf = NULL;
150 ops.len = len;
151
152 res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
153 *retlen = ops.retlen;
154 return res;
155}
156
157/*
158 * Write oob data to flash
159 */
160int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
161 size_t *retlen, uint8_t *buf)
162{
163 struct mtd_oob_ops ops;
164 int res;
165
166 ops.mode = MTD_OOB_PLACE;
167 ops.ooboffs = offs & (mtd->writesize - 1);
168 ops.ooblen = len;
169 ops.oobbuf = buf;
170 ops.datbuf = NULL;
171 ops.len = len;
172
173 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
174 *retlen = ops.retlen;
175 return res;
176}
177
553a8012
FD
178#ifdef CONFIG_NFTL_RW
179
8593fbc6
TG
180/*
181 * Write data and oob to flash
182 */
183static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
184 size_t *retlen, uint8_t *buf, uint8_t *oob)
185{
186 struct mtd_oob_ops ops;
187 int res;
188
189 ops.mode = MTD_OOB_PLACE;
190 ops.ooboffs = offs;
191 ops.ooblen = mtd->oobsize;
192 ops.oobbuf = oob;
193 ops.datbuf = buf;
194 ops.len = len;
195
196 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
197 *retlen = ops.retlen;
198 return res;
199}
200
1da177e4
LT
201/* Actual NFTL access routines */
202/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
203 * when the give Virtual Unit Chain
204 */
205static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
206{
207 /* For a given Virtual Unit Chain: find or create a free block and
208 add it to the chain */
209 /* We're passed the number of the last EUN in the chain, to save us from
210 having to look it up again */
211 u16 pot = nftl->LastFreeEUN;
212 int silly = nftl->nb_blocks;
213
214 /* Normally, we force a fold to happen before we run out of free blocks completely */
215 if (!desperate && nftl->numfreeEUNs < 2) {
216 DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
217 return 0xffff;
218 }
219
220 /* Scan for a free block */
221 do {
222 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
223 nftl->LastFreeEUN = pot;
224 nftl->numfreeEUNs--;
225 return pot;
226 }
227
228 /* This will probably point to the MediaHdr unit itself,
229 right at the beginning of the partition. But that unit
230 (and the backup unit too) should have the UCI set
231 up so that it's not selected for overwriting */
232 if (++pot > nftl->lastEUN)
233 pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
234
235 if (!silly--) {
236 printk("Argh! No free blocks found! LastFreeEUN = %d, "
97894cda 237 "FirstEUN = %d\n", nftl->LastFreeEUN,
1da177e4
LT
238 le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
239 return 0xffff;
240 }
241 } while (pot != nftl->LastFreeEUN);
242
243 return 0xffff;
244}
245
246static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
247{
f4a43cfc 248 struct mtd_info *mtd = nftl->mbd.mtd;
1da177e4
LT
249 u16 BlockMap[MAX_SECTORS_PER_UNIT];
250 unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
251 unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
252 unsigned int thisEUN;
253 int block;
254 int silly;
255 unsigned int targetEUN;
256 struct nftl_oob oob;
257 int inplace = 1;
f4a43cfc 258 size_t retlen;
1da177e4
LT
259
260 memset(BlockMap, 0xff, sizeof(BlockMap));
261 memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
262
263 thisEUN = nftl->EUNtable[thisVUC];
264
265 if (thisEUN == BLOCK_NIL) {
266 printk(KERN_WARNING "Trying to fold non-existent "
267 "Virtual Unit Chain %d!\n", thisVUC);
268 return BLOCK_NIL;
269 }
97894cda 270
1da177e4
LT
271 /* Scan to find the Erase Unit which holds the actual data for each
272 512-byte block within the Chain.
273 */
f4a43cfc 274 silly = MAX_LOOPS;
1da177e4
LT
275 targetEUN = BLOCK_NIL;
276 while (thisEUN <= nftl->lastEUN ) {
f4a43cfc 277 unsigned int status, foldmark;
1da177e4
LT
278
279 targetEUN = thisEUN;
280 for (block = 0; block < nftl->EraseSize / 512; block ++) {
8593fbc6 281 nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
f4a43cfc
TG
282 (block * 512), 16 , &retlen,
283 (char *)&oob);
1da177e4 284 if (block == 2) {
f4a43cfc
TG
285 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
286 if (foldmark == FOLD_MARK_IN_PROGRESS) {
287 DEBUG(MTD_DEBUG_LEVEL1,
288 "Write Inhibited on EUN %d\n", thisEUN);
1da177e4
LT
289 inplace = 0;
290 } else {
291 /* There's no other reason not to do inplace,
292 except ones that come later. So we don't need
293 to preserve inplace */
294 inplace = 1;
295 }
296 }
f4a43cfc 297 status = oob.b.Status | oob.b.Status1;
1da177e4
LT
298 BlockLastState[block] = status;
299
300 switch(status) {
301 case SECTOR_FREE:
302 BlockFreeFound[block] = 1;
303 break;
304
305 case SECTOR_USED:
306 if (!BlockFreeFound[block])
307 BlockMap[block] = thisEUN;
308 else
97894cda 309 printk(KERN_WARNING
1da177e4
LT
310 "SECTOR_USED found after SECTOR_FREE "
311 "in Virtual Unit Chain %d for block %d\n",
312 thisVUC, block);
313 break;
314 case SECTOR_DELETED:
315 if (!BlockFreeFound[block])
316 BlockMap[block] = BLOCK_NIL;
317 else
97894cda 318 printk(KERN_WARNING
1da177e4
LT
319 "SECTOR_DELETED found after SECTOR_FREE "
320 "in Virtual Unit Chain %d for block %d\n",
321 thisVUC, block);
322 break;
323
324 case SECTOR_IGNORE:
325 break;
326 default:
327 printk("Unknown status for block %d in EUN %d: %x\n",
328 block, thisEUN, status);
329 }
330 }
331
332 if (!silly--) {
333 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
334 thisVUC);
335 return BLOCK_NIL;
336 }
97894cda 337
1da177e4
LT
338 thisEUN = nftl->ReplUnitTable[thisEUN];
339 }
340
341 if (inplace) {
342 /* We're being asked to be a fold-in-place. Check
343 that all blocks which actually have data associated
97894cda 344 with them (i.e. BlockMap[block] != BLOCK_NIL) are
1da177e4
LT
345 either already present or SECTOR_FREE in the target
346 block. If not, we're going to have to fold out-of-place
347 anyway.
348 */
349 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
350 if (BlockLastState[block] != SECTOR_FREE &&
351 BlockMap[block] != BLOCK_NIL &&
352 BlockMap[block] != targetEUN) {
353 DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
354 "block %d was %x lastEUN, "
355 "and is in EUN %d (%s) %d\n",
356 thisVUC, block, BlockLastState[block],
97894cda 357 BlockMap[block],
1da177e4
LT
358 BlockMap[block]== targetEUN ? "==" : "!=",
359 targetEUN);
360 inplace = 0;
361 break;
362 }
363 }
364
365 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
366 pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
367 BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
368 SECTOR_FREE) {
369 DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
370 "Folding out of place.\n", targetEUN);
371 inplace = 0;
372 }
373 }
97894cda 374
1da177e4
LT
375 if (!inplace) {
376 DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
377 "Trying out-of-place\n", thisVUC);
378 /* We need to find a targetEUN to fold into. */
379 targetEUN = NFTL_findfreeblock(nftl, 1);
380 if (targetEUN == BLOCK_NIL) {
97894cda 381 /* Ouch. Now we're screwed. We need to do a
1da177e4
LT
382 fold-in-place of another chain to make room
383 for this one. We need a better way of selecting
97894cda 384 which chain to fold, because makefreeblock will
1da177e4
LT
385 only ask us to fold the same one again.
386 */
387 printk(KERN_WARNING
388 "NFTL_findfreeblock(desperate) returns 0xffff.\n");
389 return BLOCK_NIL;
390 }
391 } else {
f4a43cfc
TG
392 /* We put a fold mark in the chain we are folding only if we
393 fold in place to help the mount check code. If we do not fold in
394 place, it is possible to find the valid chain by selecting the
395 longer one */
396 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
397 oob.u.c.unused = 0xffffffff;
8593fbc6 398 nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
f4a43cfc
TG
399 8, &retlen, (char *)&oob.u);
400 }
1da177e4
LT
401
402 /* OK. We now know the location of every block in the Virtual Unit Chain,
403 and the Erase Unit into which we are supposed to be copying.
404 Go for it.
405 */
406 DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
407 for (block = 0; block < nftl->EraseSize / 512 ; block++) {
408 unsigned char movebuf[512];
409 int ret;
410
411 /* If it's in the target EUN already, or if it's pending write, do nothing */
412 if (BlockMap[block] == targetEUN ||
413 (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
414 continue;
415 }
416
f4a43cfc 417 /* copy only in non free block (free blocks can only
1da177e4 418 happen in case of media errors or deleted blocks) */
f4a43cfc
TG
419 if (BlockMap[block] == BLOCK_NIL)
420 continue;
421
422 ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
423 512, &retlen, movebuf);
9a1fcdfd 424 if (ret < 0 && ret != -EUCLEAN) {
f4a43cfc
TG
425 ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
426 + (block * 512), 512, &retlen,
427 movebuf);
428 if (ret != -EIO)
429 printk("Error went away on retry.\n");
430 }
1da177e4
LT
431 memset(&oob, 0xff, sizeof(struct nftl_oob));
432 oob.b.Status = oob.b.Status1 = SECTOR_USED;
9223a456 433
8593fbc6
TG
434 nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
435 (block * 512), 512, &retlen, movebuf, (char *)&oob);
1da177e4 436 }
97894cda 437
f4a43cfc
TG
438 /* add the header so that it is now a valid chain */
439 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
440 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
97894cda 441
8593fbc6 442 nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
f4a43cfc 443 8, &retlen, (char *)&oob.u);
1da177e4
LT
444
445 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
446
97894cda 447 /* At this point, we have two different chains for this Virtual Unit, and no way to tell
1da177e4
LT
448 them apart. If we crash now, we get confused. However, both contain the same data, so we
449 shouldn't actually lose data in this case. It's just that when we load up on a medium which
450 has duplicate chains, we need to free one of the chains because it's not necessary any more.
451 */
452 thisEUN = nftl->EUNtable[thisVUC];
453 DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
454
97894cda 455 /* For each block in the old chain (except the targetEUN of course),
1da177e4
LT
456 free it and make it available for future use */
457 while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
458 unsigned int EUNtmp;
459
f4a43cfc 460 EUNtmp = nftl->ReplUnitTable[thisEUN];
1da177e4 461
f4a43cfc 462 if (NFTL_formatblock(nftl, thisEUN) < 0) {
1da177e4
LT
463 /* could not erase : mark block as reserved
464 */
465 nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
f4a43cfc 466 } else {
1da177e4
LT
467 /* correctly erased : mark it as free */
468 nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
469 nftl->numfreeEUNs++;
f4a43cfc
TG
470 }
471 thisEUN = EUNtmp;
1da177e4 472 }
97894cda 473
1da177e4
LT
474 /* Make this the new start of chain for thisVUC */
475 nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
476 nftl->EUNtable[thisVUC] = targetEUN;
477
478 return targetEUN;
479}
480
481static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
482{
97894cda 483 /* This is the part that needs some cleverness applied.
1da177e4
LT
484 For now, I'm doing the minimum applicable to actually
485 get the thing to work.
486 Wear-levelling and other clever stuff needs to be implemented
487 and we also need to do some assessment of the results when
488 the system loses power half-way through the routine.
489 */
490 u16 LongestChain = 0;
491 u16 ChainLength = 0, thislen;
492 u16 chain, EUN;
493
494 for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
495 EUN = nftl->EUNtable[chain];
496 thislen = 0;
497
498 while (EUN <= nftl->lastEUN) {
499 thislen++;
500 //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
501 EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
502 if (thislen > 0xff00) {
503 printk("Endless loop in Virtual Chain %d: Unit %x\n",
504 chain, EUN);
505 }
506 if (thislen > 0xff10) {
507 /* Actually, don't return failure. Just ignore this chain and
508 get on with it. */
509 thislen = 0;
510 break;
511 }
512 }
513
514 if (thislen > ChainLength) {
515 //printk("New longest chain is %d with length %d\n", chain, thislen);
516 ChainLength = thislen;
517 LongestChain = chain;
518 }
519 }
520
521 if (ChainLength < 2) {
522 printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
523 "Failing request\n");
524 return 0xffff;
525 }
526
527 return NFTL_foldchain (nftl, LongestChain, pendingblock);
528}
529
97894cda 530/* NFTL_findwriteunit: Return the unit number into which we can write
1da177e4
LT
531 for this block. Make it available if it isn't already
532*/
533static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
534{
535 u16 lastEUN;
536 u16 thisVUC = block / (nftl->EraseSize / 512);
f4a43cfc 537 struct mtd_info *mtd = nftl->mbd.mtd;
1da177e4
LT
538 unsigned int writeEUN;
539 unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
540 size_t retlen;
541 int silly, silly2 = 3;
542 struct nftl_oob oob;
543
544 do {
545 /* Scan the media to find a unit in the VUC which has
546 a free space for the block in question.
547 */
548
97894cda 549 /* This condition catches the 0x[7f]fff cases, as well as
1da177e4
LT
550 being a sanity check for past-end-of-media access
551 */
552 lastEUN = BLOCK_NIL;
553 writeEUN = nftl->EUNtable[thisVUC];
f4a43cfc 554 silly = MAX_LOOPS;
1da177e4
LT
555 while (writeEUN <= nftl->lastEUN) {
556 struct nftl_bci bci;
557 size_t retlen;
f4a43cfc 558 unsigned int status;
1da177e4
LT
559
560 lastEUN = writeEUN;
561
8593fbc6 562 nftl_read_oob(mtd,
f4a43cfc
TG
563 (writeEUN * nftl->EraseSize) + blockofs,
564 8, &retlen, (char *)&bci);
97894cda 565
1da177e4
LT
566 DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
567 block , writeEUN, le16_to_cpu(bci.Status));
568
f4a43cfc 569 status = bci.Status | bci.Status1;
1da177e4
LT
570 switch(status) {
571 case SECTOR_FREE:
572 return writeEUN;
573
574 case SECTOR_DELETED:
575 case SECTOR_USED:
576 case SECTOR_IGNORE:
577 break;
578 default:
579 // Invalid block. Don't use it any more. Must implement.
97894cda 580 break;
1da177e4 581 }
97894cda
TG
582
583 if (!silly--) {
1da177e4
LT
584 printk(KERN_WARNING
585 "Infinite loop in Virtual Unit Chain 0x%x\n",
586 thisVUC);
587 return 0xffff;
588 }
589
590 /* Skip to next block in chain */
591 writeEUN = nftl->ReplUnitTable[writeEUN];
592 }
593
97894cda 594 /* OK. We didn't find one in the existing chain, or there
1da177e4
LT
595 is no existing chain. */
596
597 /* Try to find an already-free block */
598 writeEUN = NFTL_findfreeblock(nftl, 0);
599
600 if (writeEUN == BLOCK_NIL) {
601 /* That didn't work - there were no free blocks just
602 waiting to be picked up. We're going to have to fold
603 a chain to make room.
604 */
605
606 /* First remember the start of this chain */
607 //u16 startEUN = nftl->EUNtable[thisVUC];
97894cda 608
1da177e4
LT
609 //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
610 writeEUN = NFTL_makefreeblock(nftl, 0xffff);
611
612 if (writeEUN == BLOCK_NIL) {
97894cda 613 /* OK, we accept that the above comment is
1da177e4
LT
614 lying - there may have been free blocks
615 last time we called NFTL_findfreeblock(),
616 but they are reserved for when we're
617 desperate. Well, now we're desperate.
618 */
619 DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
620 writeEUN = NFTL_findfreeblock(nftl, 1);
621 }
622 if (writeEUN == BLOCK_NIL) {
623 /* Ouch. This should never happen - we should
97894cda
TG
624 always be able to make some room somehow.
625 If we get here, we've allocated more storage
1da177e4
LT
626 space than actual media, or our makefreeblock
627 routine is missing something.
628 */
629 printk(KERN_WARNING "Cannot make free space.\n");
630 return BLOCK_NIL;
97894cda 631 }
1da177e4
LT
632 //printk("Restarting scan\n");
633 lastEUN = BLOCK_NIL;
634 continue;
635 }
636
637 /* We've found a free block. Insert it into the chain. */
97894cda 638
1da177e4 639 if (lastEUN != BLOCK_NIL) {
f4a43cfc 640 thisVUC |= 0x8000; /* It's a replacement block */
1da177e4 641 } else {
f4a43cfc
TG
642 /* The first block in a new chain */
643 nftl->EUNtable[thisVUC] = writeEUN;
1da177e4
LT
644 }
645
646 /* set up the actual EUN we're writing into */
647 /* Both in our cache... */
648 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
649
650 /* ... and on the flash itself */
8593fbc6 651 nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
f4a43cfc 652 &retlen, (char *)&oob.u);
1da177e4
LT
653
654 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
655
8593fbc6 656 nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
f4a43cfc 657 &retlen, (char *)&oob.u);
1da177e4 658
f4a43cfc 659 /* we link the new block to the chain only after the
1da177e4
LT
660 block is ready. It avoids the case where the chain
661 could point to a free block */
f4a43cfc 662 if (lastEUN != BLOCK_NIL) {
1da177e4
LT
663 /* Both in our cache... */
664 nftl->ReplUnitTable[lastEUN] = writeEUN;
665 /* ... and on the flash itself */
8593fbc6 666 nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
f4a43cfc 667 8, &retlen, (char *)&oob.u);
1da177e4
LT
668
669 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
670 = cpu_to_le16(writeEUN);
671
8593fbc6 672 nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
f4a43cfc 673 8, &retlen, (char *)&oob.u);
1da177e4
LT
674 }
675
676 return writeEUN;
677
678 } while (silly2--);
679
680 printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
681 thisVUC);
682 return 0xffff;
683}
684
685static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
686 char *buffer)
687{
688 struct NFTLrecord *nftl = (void *)mbd;
689 u16 writeEUN;
690 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
691 size_t retlen;
692 struct nftl_oob oob;
693
694 writeEUN = NFTL_findwriteunit(nftl, block);
695
696 if (writeEUN == BLOCK_NIL) {
697 printk(KERN_WARNING
698 "NFTL_writeblock(): Cannot find block to write to\n");
699 /* If we _still_ haven't got a block to use, we're screwed */
700 return 1;
701 }
702
703 memset(&oob, 0xff, sizeof(struct nftl_oob));
704 oob.b.Status = oob.b.Status1 = SECTOR_USED;
1da177e4 705
8593fbc6
TG
706 nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
707 512, &retlen, (char *)buffer, (char *)&oob);
1da177e4
LT
708 return 0;
709}
710#endif /* CONFIG_NFTL_RW */
711
712static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
713 char *buffer)
714{
715 struct NFTLrecord *nftl = (void *)mbd;
f4a43cfc 716 struct mtd_info *mtd = nftl->mbd.mtd;
1da177e4
LT
717 u16 lastgoodEUN;
718 u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
719 unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
f4a43cfc 720 unsigned int status;
1da177e4 721 int silly = MAX_LOOPS;
f4a43cfc
TG
722 size_t retlen;
723 struct nftl_bci bci;
1da177e4
LT
724
725 lastgoodEUN = BLOCK_NIL;
726
f4a43cfc 727 if (thisEUN != BLOCK_NIL) {
1da177e4 728 while (thisEUN < nftl->nb_blocks) {
8593fbc6 729 if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
f4a43cfc
TG
730 blockofs, 8, &retlen,
731 (char *)&bci) < 0)
1da177e4
LT
732 status = SECTOR_IGNORE;
733 else
734 status = bci.Status | bci.Status1;
735
736 switch (status) {
737 case SECTOR_FREE:
738 /* no modification of a sector should follow a free sector */
739 goto the_end;
740 case SECTOR_DELETED:
741 lastgoodEUN = BLOCK_NIL;
742 break;
743 case SECTOR_USED:
744 lastgoodEUN = thisEUN;
745 break;
746 case SECTOR_IGNORE:
747 break;
748 default:
749 printk("Unknown status for block %ld in EUN %d: %x\n",
750 block, thisEUN, status);
751 break;
752 }
753
754 if (!silly--) {
755 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
756 block / (nftl->EraseSize / 512));
757 return 1;
758 }
759 thisEUN = nftl->ReplUnitTable[thisEUN];
760 }
f4a43cfc 761 }
1da177e4
LT
762
763 the_end:
764 if (lastgoodEUN == BLOCK_NIL) {
765 /* the requested block is not on the media, return all 0x00 */
766 memset(buffer, 0, 512);
767 } else {
768 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
769 size_t retlen;
9a1fcdfd
TG
770 int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
771
772 if (res < 0 && res != -EUCLEAN)
1da177e4
LT
773 return -EIO;
774 }
775 return 0;
776}
777
778static int nftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
779{
780 struct NFTLrecord *nftl = (void *)dev;
781
782 geo->heads = nftl->heads;
783 geo->sectors = nftl->sectors;
784 geo->cylinders = nftl->cylinders;
785
786 return 0;
787}
788
789/****************************************************************************
790 *
791 * Module stuff
792 *
793 ****************************************************************************/
794
795
796static struct mtd_blktrans_ops nftl_tr = {
797 .name = "nftl",
798 .major = NFTL_MAJOR,
799 .part_bits = NFTL_PARTN_BITS,
19187672 800 .blksize = 512,
1da177e4
LT
801 .getgeo = nftl_getgeo,
802 .readsect = nftl_readblock,
803#ifdef CONFIG_NFTL_RW
804 .writesect = nftl_writeblock,
805#endif
806 .add_mtd = nftl_add_mtd,
807 .remove_dev = nftl_remove_dev,
808 .owner = THIS_MODULE,
809};
810
811extern char nftlmountrev[];
812
813static int __init init_nftl(void)
814{
97894cda 815 printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev);
1da177e4
LT
816
817 return register_mtd_blktrans(&nftl_tr);
818}
819
820static void __exit cleanup_nftl(void)
821{
822 deregister_mtd_blktrans(&nftl_tr);
823}
824
825module_init(init_nftl);
826module_exit(cleanup_nftl);
827
828MODULE_LICENSE("GPL");
829MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
830MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");