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