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