Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ftl.c
Go to the documentation of this file.
1 /* This version ported to the Linux-MTD system by [email protected]
2  *
3  * Fixes: Arnaldo Carvalho de Melo <[email protected]>
4  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
5  *
6  * Based on:
7  */
8 /*======================================================================
9 
10  A Flash Translation Layer memory card driver
11 
12  This driver implements a disk-like block device driver with an
13  apparent block size of 512 bytes for flash memory cards.
14 
15  ftl_cs.c 1.62 2000/02/01 00:59:04
16 
17  The contents of this file are subject to the Mozilla Public
18  License Version 1.1 (the "License"); you may not use this file
19  except in compliance with the License. You may obtain a copy of
20  the License at http://www.mozilla.org/MPL/
21 
22  Software distributed under the License is distributed on an "AS
23  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
24  implied. See the License for the specific language governing
25  rights and limitations under the License.
26 
27  The initial developer of the original code is David A. Hinds
28  <[email protected]>. Portions created by David A. Hinds
29  are Copyright © 1999 David A. Hinds. All Rights Reserved.
30 
31  Alternatively, the contents of this file may be used under the
32  terms of the GNU General Public License version 2 (the "GPL"), in
33  which case the provisions of the GPL are applicable instead of the
34  above. If you wish to allow the use of your version of this file
35  only under the terms of the GPL and not to allow others to use
36  your version of this file under the MPL, indicate your decision
37  by deleting the provisions above and replace them with the notice
38  and other provisions required by the GPL. If you do not delete
39  the provisions above, a recipient may use your version of this
40  file under either the MPL or the GPL.
41 
42  LEGAL NOTE: The FTL format is patented by M-Systems. They have
43  granted a license for its use with PCMCIA devices:
44 
45  "M-Systems grants a royalty-free, non-exclusive license under
46  any presently existing M-Systems intellectual property rights
47  necessary for the design and development of FTL-compatible
48  drivers, file systems and utilities using the data formats with
49  PCMCIA PC Cards as described in the PCMCIA Flash Translation
50  Layer (FTL) Specification."
51 
52  Use of the FTL format for non-PCMCIA applications may be an
53  infringement of these patents. For additional information,
54  contact M-Systems directly. M-Systems since acquired by Sandisk.
55 
56 ======================================================================*/
57 #include <linux/mtd/blktrans.h>
58 #include <linux/module.h>
59 #include <linux/mtd/mtd.h>
60 /*#define PSYCHO_DEBUG */
61 
62 #include <linux/kernel.h>
63 #include <linux/ptrace.h>
64 #include <linux/slab.h>
65 #include <linux/string.h>
66 #include <linux/timer.h>
67 #include <linux/major.h>
68 #include <linux/fs.h>
69 #include <linux/init.h>
70 #include <linux/hdreg.h>
71 #include <linux/vmalloc.h>
72 #include <linux/blkpg.h>
73 #include <asm/uaccess.h>
74 
75 #include <linux/mtd/ftl.h>
76 
77 /*====================================================================*/
78 
79 /* Parameters that can be set with 'insmod' */
80 static int shuffle_freq = 50;
81 module_param(shuffle_freq, int, 0);
82 
83 /*====================================================================*/
84 
85 /* Major device # for FTL device */
86 #ifndef FTL_MAJOR
87 #define FTL_MAJOR 44
88 #endif
89 
90 
91 /*====================================================================*/
92 
93 /* Maximum number of separate memory devices we'll allow */
94 #define MAX_DEV 4
95 
96 /* Maximum number of regions per device */
97 #define MAX_REGION 4
98 
99 /* Maximum number of partitions in an FTL region */
100 #define PART_BITS 4
101 
102 /* Maximum number of outstanding erase requests per socket */
103 #define MAX_ERASE 8
104 
105 /* Sector size -- shouldn't need to change */
106 #define SECTOR_SIZE 512
107 
108 
109 /* Each memory region corresponds to a minor device */
110 typedef struct partition_t {
116  struct eun_info_t {
121  } *EUNInfo;
122  struct xfer_info_t {
126  } *XferInfo;
132 } partition_t;
133 
134 /* Partition state flags */
135 #define FTL_FORMATTED 0x01
136 
137 /* Transfer unit states */
138 #define XFER_UNKNOWN 0x00
139 #define XFER_ERASING 0x01
140 #define XFER_ERASED 0x02
141 #define XFER_PREPARED 0x03
142 #define XFER_FAILED 0x04
143 
144 /*====================================================================*/
145 
146 
147 static void ftl_erase_callback(struct erase_info *done);
148 
149 
150 /*======================================================================
151 
152  Scan_header() checks to see if a memory region contains an FTL
153  partition. build_maps() reads all the erase unit headers, builds
154  the erase unit map, and then builds the virtual page map.
155 
156 ======================================================================*/
157 
158 static int scan_header(partition_t *part)
159 {
161  loff_t offset, max_offset;
162  size_t ret;
163  int err;
164  part->header.FormattedSize = 0;
165  max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
166  /* Search first megabyte for a valid FTL header */
167  for (offset = 0;
168  (offset + sizeof(header)) < max_offset;
169  offset += part->mbd.mtd->erasesize ? : 0x2000) {
170 
171  err = mtd_read(part->mbd.mtd, offset, sizeof(header), &ret,
172  (unsigned char *)&header);
173 
174  if (err)
175  return err;
176 
177  if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
178  }
179 
180  if (offset == max_offset) {
181  printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
182  return -ENOENT;
183  }
184  if (header.BlockSize != 9 ||
185  (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
186  (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
187  printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
188  return -1;
189  }
190  if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
191  printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
192  1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
193  return -1;
194  }
195  part->header = header;
196  return 0;
197 }
198 
199 static int build_maps(partition_t *part)
200 {
201  erase_unit_header_t header;
202  uint16_t xvalid, xtrans, i;
203  unsigned blocks, j;
204  int hdr_ok, ret = -1;
205  ssize_t retval;
206  loff_t offset;
207 
208  /* Set up erase unit maps */
209  part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
210  part->header.NumTransferUnits;
211  part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
212  GFP_KERNEL);
213  if (!part->EUNInfo)
214  goto out;
215  for (i = 0; i < part->DataUnits; i++)
216  part->EUNInfo[i].Offset = 0xffffffff;
217  part->XferInfo =
218  kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
219  GFP_KERNEL);
220  if (!part->XferInfo)
221  goto out_EUNInfo;
222 
223  xvalid = xtrans = 0;
224  for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
225  offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
226  << part->header.EraseUnitSize);
227  ret = mtd_read(part->mbd.mtd, offset, sizeof(header), &retval,
228  (unsigned char *)&header);
229 
230  if (ret)
231  goto out_XferInfo;
232 
233  ret = -1;
234  /* Is this a transfer partition? */
235  hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
236  if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
237  (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
238  part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
239  part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
240  le32_to_cpu(header.EraseCount);
241  xvalid++;
242  } else {
243  if (xtrans == part->header.NumTransferUnits) {
244  printk(KERN_NOTICE "ftl_cs: format error: too many "
245  "transfer units!\n");
246  goto out_XferInfo;
247  }
248  if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
249  part->XferInfo[xtrans].state = XFER_PREPARED;
250  part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
251  } else {
252  part->XferInfo[xtrans].state = XFER_UNKNOWN;
253  /* Pick anything reasonable for the erase count */
254  part->XferInfo[xtrans].EraseCount =
256  }
257  part->XferInfo[xtrans].Offset = offset;
258  xtrans++;
259  }
260  }
261  /* Check for format trouble */
262  header = part->header;
263  if ((xtrans != header.NumTransferUnits) ||
264  (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
265  printk(KERN_NOTICE "ftl_cs: format error: erase units "
266  "don't add up!\n");
267  goto out_XferInfo;
268  }
269 
270  /* Set up virtual page map */
271  blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
272  part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t));
273  if (!part->VirtualBlockMap)
274  goto out_XferInfo;
275 
276  memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
277  part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
278 
279  part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t),
280  GFP_KERNEL);
281  if (!part->bam_cache)
282  goto out_VirtualBlockMap;
283 
284  part->bam_index = 0xffff;
285  part->FreeTotal = 0;
286 
287  for (i = 0; i < part->DataUnits; i++) {
288  part->EUNInfo[i].Free = 0;
289  part->EUNInfo[i].Deleted = 0;
290  offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
291 
292  ret = mtd_read(part->mbd.mtd, offset,
293  part->BlocksPerUnit * sizeof(uint32_t), &retval,
294  (unsigned char *)part->bam_cache);
295 
296  if (ret)
297  goto out_bam_cache;
298 
299  for (j = 0; j < part->BlocksPerUnit; j++) {
300  if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
301  part->EUNInfo[i].Free++;
302  part->FreeTotal++;
303  } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
304  (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
306  (i << header.EraseUnitSize) + (j << header.BlockSize);
307  else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
308  part->EUNInfo[i].Deleted++;
309  }
310  }
311 
312  ret = 0;
313  goto out;
314 
315 out_bam_cache:
316  kfree(part->bam_cache);
317 out_VirtualBlockMap:
318  vfree(part->VirtualBlockMap);
319 out_XferInfo:
320  kfree(part->XferInfo);
321 out_EUNInfo:
322  kfree(part->EUNInfo);
323 out:
324  return ret;
325 } /* build_maps */
326 
327 /*======================================================================
328 
329  Erase_xfer() schedules an asynchronous erase operation for a
330  transfer unit.
331 
332 ======================================================================*/
333 
334 static int erase_xfer(partition_t *part,
335  uint16_t xfernum)
336 {
337  int ret;
338  struct xfer_info_t *xfer;
339  struct erase_info *erase;
340 
341  xfer = &part->XferInfo[xfernum];
342  pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
343  xfer->state = XFER_ERASING;
344 
345  /* Is there a free erase slot? Always in MTD. */
346 
347 
348  erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
349  if (!erase)
350  return -ENOMEM;
351 
352  erase->mtd = part->mbd.mtd;
353  erase->callback = ftl_erase_callback;
354  erase->addr = xfer->Offset;
355  erase->len = 1 << part->header.EraseUnitSize;
356  erase->priv = (u_long)part;
357 
358  ret = mtd_erase(part->mbd.mtd, erase);
359 
360  if (!ret)
361  xfer->EraseCount++;
362  else
363  kfree(erase);
364 
365  return ret;
366 } /* erase_xfer */
367 
368 /*======================================================================
369 
370  Prepare_xfer() takes a freshly erased transfer unit and gives
371  it an appropriate header.
372 
373 ======================================================================*/
374 
375 static void ftl_erase_callback(struct erase_info *erase)
376 {
377  partition_t *part;
378  struct xfer_info_t *xfer;
379  int i;
380 
381  /* Look up the transfer unit */
382  part = (partition_t *)(erase->priv);
383 
384  for (i = 0; i < part->header.NumTransferUnits; i++)
385  if (part->XferInfo[i].Offset == erase->addr) break;
386 
387  if (i == part->header.NumTransferUnits) {
388  printk(KERN_NOTICE "ftl_cs: internal error: "
389  "erase lookup failed!\n");
390  return;
391  }
392 
393  xfer = &part->XferInfo[i];
394  if (erase->state == MTD_ERASE_DONE)
395  xfer->state = XFER_ERASED;
396  else {
397  xfer->state = XFER_FAILED;
398  printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
399  erase->state);
400  }
401 
402  kfree(erase);
403 
404 } /* ftl_erase_callback */
405 
406 static int prepare_xfer(partition_t *part, int i)
407 {
408  erase_unit_header_t header;
409  struct xfer_info_t *xfer;
410  int nbam, ret;
411  uint32_t ctl;
412  ssize_t retlen;
413  loff_t offset;
414 
415  xfer = &part->XferInfo[i];
416  xfer->state = XFER_FAILED;
417 
418  pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
419 
420  /* Write the transfer unit header */
421  header = part->header;
422  header.LogicalEUN = cpu_to_le16(0xffff);
423  header.EraseCount = cpu_to_le32(xfer->EraseCount);
424 
425  ret = mtd_write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen,
426  (u_char *)&header);
427 
428  if (ret) {
429  return ret;
430  }
431 
432  /* Write the BAM stub */
433  nbam = (part->BlocksPerUnit * sizeof(uint32_t) +
435 
436  offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
437  ctl = cpu_to_le32(BLOCK_CONTROL);
438 
439  for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
440 
441  ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
442  (u_char *)&ctl);
443 
444  if (ret)
445  return ret;
446  }
447  xfer->state = XFER_PREPARED;
448  return 0;
449 
450 } /* prepare_xfer */
451 
452 /*======================================================================
453 
454  Copy_erase_unit() takes a full erase block and a transfer unit,
455  copies everything to the transfer unit, then swaps the block
456  pointers.
457 
458  All data blocks are copied to the corresponding blocks in the
459  target unit, so the virtual block map does not need to be
460  updated.
461 
462 ======================================================================*/
463 
464 static int copy_erase_unit(partition_t *part, uint16_t srcunit,
465  uint16_t xferunit)
466 {
468  struct eun_info_t *eun;
469  struct xfer_info_t *xfer;
470  uint32_t src, dest, free, i;
471  uint16_t unit;
472  int ret;
473  ssize_t retlen;
474  loff_t offset;
475  uint16_t srcunitswap = cpu_to_le16(srcunit);
476 
477  eun = &part->EUNInfo[srcunit];
478  xfer = &part->XferInfo[xferunit];
479  pr_debug("ftl_cs: copying block 0x%x to 0x%x\n",
480  eun->Offset, xfer->Offset);
481 
482 
483  /* Read current BAM */
484  if (part->bam_index != srcunit) {
485 
486  offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
487 
488  ret = mtd_read(part->mbd.mtd, offset,
489  part->BlocksPerUnit * sizeof(uint32_t), &retlen,
490  (u_char *)(part->bam_cache));
491 
492  /* mark the cache bad, in case we get an error later */
493  part->bam_index = 0xffff;
494 
495  if (ret) {
496  printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
497  return ret;
498  }
499  }
500 
501  /* Write the LogicalEUN for the transfer unit */
502  xfer->state = XFER_UNKNOWN;
503  offset = xfer->Offset + 20; /* Bad! */
504  unit = cpu_to_le16(0x7fff);
505 
506  ret = mtd_write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen,
507  (u_char *)&unit);
508 
509  if (ret) {
510  printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
511  return ret;
512  }
513 
514  /* Copy all data blocks from source unit to transfer unit */
515  src = eun->Offset; dest = xfer->Offset;
516 
517  free = 0;
518  ret = 0;
519  for (i = 0; i < part->BlocksPerUnit; i++) {
520  switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
521  case BLOCK_CONTROL:
522  /* This gets updated later */
523  break;
524  case BLOCK_DATA:
525  case BLOCK_REPLACEMENT:
526  ret = mtd_read(part->mbd.mtd, src, SECTOR_SIZE, &retlen,
527  (u_char *)buf);
528  if (ret) {
529  printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
530  return ret;
531  }
532 
533 
534  ret = mtd_write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen,
535  (u_char *)buf);
536  if (ret) {
537  printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
538  return ret;
539  }
540 
541  break;
542  default:
543  /* All other blocks must be free */
544  part->bam_cache[i] = cpu_to_le32(0xffffffff);
545  free++;
546  break;
547  }
548  src += SECTOR_SIZE;
549  dest += SECTOR_SIZE;
550  }
551 
552  /* Write the BAM to the transfer unit */
553  ret = mtd_write(part->mbd.mtd,
554  xfer->Offset + le32_to_cpu(part->header.BAMOffset),
555  part->BlocksPerUnit * sizeof(int32_t),
556  &retlen,
557  (u_char *)part->bam_cache);
558  if (ret) {
559  printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
560  return ret;
561  }
562 
563 
564  /* All clear? Then update the LogicalEUN again */
565  ret = mtd_write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
566  &retlen, (u_char *)&srcunitswap);
567 
568  if (ret) {
569  printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
570  return ret;
571  }
572 
573 
574  /* Update the maps and usage stats*/
575  i = xfer->EraseCount;
576  xfer->EraseCount = eun->EraseCount;
577  eun->EraseCount = i;
578  i = xfer->Offset;
579  xfer->Offset = eun->Offset;
580  eun->Offset = i;
581  part->FreeTotal -= eun->Free;
582  part->FreeTotal += free;
583  eun->Free = free;
584  eun->Deleted = 0;
585 
586  /* Now, the cache should be valid for the new block */
587  part->bam_index = srcunit;
588 
589  return 0;
590 } /* copy_erase_unit */
591 
592 /*======================================================================
593 
594  reclaim_block() picks a full erase unit and a transfer unit and
595  then calls copy_erase_unit() to copy one to the other. Then, it
596  schedules an erase on the expired block.
597 
598  What's a good way to decide which transfer unit and which erase
599  unit to use? Beats me. My way is to always pick the transfer
600  unit with the fewest erases, and usually pick the data unit with
601  the most deleted blocks. But with a small probability, pick the
602  oldest data unit instead. This means that we generally postpone
603  the next reclamation as long as possible, but shuffle static
604  stuff around a bit for wear leveling.
605 
606 ======================================================================*/
607 
608 static int reclaim_block(partition_t *part)
609 {
610  uint16_t i, eun, xfer;
611  uint32_t best;
612  int queued, ret;
613 
614  pr_debug("ftl_cs: reclaiming space...\n");
615  pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits);
616  /* Pick the least erased transfer unit */
617  best = 0xffffffff; xfer = 0xffff;
618  do {
619  queued = 0;
620  for (i = 0; i < part->header.NumTransferUnits; i++) {
621  int n=0;
622  if (part->XferInfo[i].state == XFER_UNKNOWN) {
623  pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i);
624  n=1;
625  erase_xfer(part, i);
626  }
627  if (part->XferInfo[i].state == XFER_ERASING) {
628  pr_debug("XferInfo[%d].state == XFER_ERASING\n",i);
629  n=1;
630  queued = 1;
631  }
632  else if (part->XferInfo[i].state == XFER_ERASED) {
633  pr_debug("XferInfo[%d].state == XFER_ERASED\n",i);
634  n=1;
635  prepare_xfer(part, i);
636  }
637  if (part->XferInfo[i].state == XFER_PREPARED) {
638  pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i);
639  n=1;
640  if (part->XferInfo[i].EraseCount <= best) {
641  best = part->XferInfo[i].EraseCount;
642  xfer = i;
643  }
644  }
645  if (!n)
646  pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
647 
648  }
649  if (xfer == 0xffff) {
650  if (queued) {
651  pr_debug("ftl_cs: waiting for transfer "
652  "unit to be prepared...\n");
653  mtd_sync(part->mbd.mtd);
654  } else {
655  static int ne = 0;
656  if (++ne < 5)
657  printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
658  "suitable transfer units!\n");
659  else
660  pr_debug("ftl_cs: reclaim failed: no "
661  "suitable transfer units!\n");
662 
663  return -EIO;
664  }
665  }
666  } while (xfer == 0xffff);
667 
668  eun = 0;
669  if ((jiffies % shuffle_freq) == 0) {
670  pr_debug("ftl_cs: recycling freshest block...\n");
671  best = 0xffffffff;
672  for (i = 0; i < part->DataUnits; i++)
673  if (part->EUNInfo[i].EraseCount <= best) {
674  best = part->EUNInfo[i].EraseCount;
675  eun = i;
676  }
677  } else {
678  best = 0;
679  for (i = 0; i < part->DataUnits; i++)
680  if (part->EUNInfo[i].Deleted >= best) {
681  best = part->EUNInfo[i].Deleted;
682  eun = i;
683  }
684  if (best == 0) {
685  static int ne = 0;
686  if (++ne < 5)
687  printk(KERN_NOTICE "ftl_cs: reclaim failed: "
688  "no free blocks!\n");
689  else
690  pr_debug("ftl_cs: reclaim failed: "
691  "no free blocks!\n");
692 
693  return -EIO;
694  }
695  }
696  ret = copy_erase_unit(part, eun, xfer);
697  if (!ret)
698  erase_xfer(part, xfer);
699  else
700  printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
701  return ret;
702 } /* reclaim_block */
703 
704 /*======================================================================
705 
706  Find_free() searches for a free block. If necessary, it updates
707  the BAM cache for the erase unit containing the free block. It
708  returns the block index -- the erase unit is just the currently
709  cached unit. If there are no free blocks, it returns 0 -- this
710  is never a valid data block because it contains the header.
711 
712 ======================================================================*/
713 
714 #ifdef PSYCHO_DEBUG
715 static void dump_lists(partition_t *part)
716 {
717  int i;
718  printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
719  for (i = 0; i < part->DataUnits; i++)
720  printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
721  "%d deleted\n", i,
722  part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
723  part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
724 }
725 #endif
726 
727 static uint32_t find_free(partition_t *part)
728 {
729  uint16_t stop, eun;
730  uint32_t blk;
731  size_t retlen;
732  int ret;
733 
734  /* Find an erase unit with some free space */
735  stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
736  eun = stop;
737  do {
738  if (part->EUNInfo[eun].Free != 0) break;
739  /* Wrap around at end of table */
740  if (++eun == part->DataUnits) eun = 0;
741  } while (eun != stop);
742 
743  if (part->EUNInfo[eun].Free == 0)
744  return 0;
745 
746  /* Is this unit's BAM cached? */
747  if (eun != part->bam_index) {
748  /* Invalidate cache */
749  part->bam_index = 0xffff;
750 
751  ret = mtd_read(part->mbd.mtd,
752  part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
753  part->BlocksPerUnit * sizeof(uint32_t),
754  &retlen,
755  (u_char *)(part->bam_cache));
756 
757  if (ret) {
758  printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
759  return 0;
760  }
761  part->bam_index = eun;
762  }
763 
764  /* Find a free block */
765  for (blk = 0; blk < part->BlocksPerUnit; blk++)
766  if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
767  if (blk == part->BlocksPerUnit) {
768 #ifdef PSYCHO_DEBUG
769  static int ne = 0;
770  if (++ne == 1)
771  dump_lists(part);
772 #endif
773  printk(KERN_NOTICE "ftl_cs: bad free list!\n");
774  return 0;
775  }
776  pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun);
777  return blk;
778 
779 } /* find_free */
780 
781 
782 /*======================================================================
783 
784  Read a series of sectors from an FTL partition.
785 
786 ======================================================================*/
787 
788 static int ftl_read(partition_t *part, caddr_t buffer,
789  u_long sector, u_long nblocks)
790 {
791  uint32_t log_addr, bsize;
792  u_long i;
793  int ret;
794  size_t offset, retlen;
795 
796  pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
797  part, sector, nblocks);
798  if (!(part->state & FTL_FORMATTED)) {
799  printk(KERN_NOTICE "ftl_cs: bad partition\n");
800  return -EIO;
801  }
802  bsize = 1 << part->header.EraseUnitSize;
803 
804  for (i = 0; i < nblocks; i++) {
805  if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
806  printk(KERN_NOTICE "ftl_cs: bad read offset\n");
807  return -EIO;
808  }
809  log_addr = part->VirtualBlockMap[sector+i];
810  if (log_addr == 0xffffffff)
811  memset(buffer, 0, SECTOR_SIZE);
812  else {
813  offset = (part->EUNInfo[log_addr / bsize].Offset
814  + (log_addr % bsize));
815  ret = mtd_read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
816  (u_char *)buffer);
817 
818  if (ret) {
819  printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
820  return ret;
821  }
822  }
823  buffer += SECTOR_SIZE;
824  }
825  return 0;
826 } /* ftl_read */
827 
828 /*======================================================================
829 
830  Write a series of sectors to an FTL partition
831 
832 ======================================================================*/
833 
834 static int set_bam_entry(partition_t *part, uint32_t log_addr,
835  uint32_t virt_addr)
836 {
837  uint32_t bsize, blk, le_virt_addr;
838 #ifdef PSYCHO_DEBUG
839  uint32_t old_addr;
840 #endif
841  uint16_t eun;
842  int ret;
843  size_t retlen, offset;
844 
845  pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
846  part, log_addr, virt_addr);
847  bsize = 1 << part->header.EraseUnitSize;
848  eun = log_addr / bsize;
849  blk = (log_addr % bsize) / SECTOR_SIZE;
850  offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
851  le32_to_cpu(part->header.BAMOffset));
852 
853 #ifdef PSYCHO_DEBUG
854  ret = mtd_read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
855  (u_char *)&old_addr);
856  if (ret) {
857  printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
858  return ret;
859  }
860  old_addr = le32_to_cpu(old_addr);
861 
862  if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
863  ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
864  (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
865  static int ne = 0;
866  if (++ne < 5) {
867  printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
868  printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
869  ", new = 0x%x\n", log_addr, old_addr, virt_addr);
870  }
871  return -EIO;
872  }
873 #endif
874  le_virt_addr = cpu_to_le32(virt_addr);
875  if (part->bam_index == eun) {
876 #ifdef PSYCHO_DEBUG
877  if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
878  static int ne = 0;
879  if (++ne < 5) {
880  printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
881  "inconsistency!\n");
882  printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
883  " = 0x%x\n",
884  le32_to_cpu(part->bam_cache[blk]), old_addr);
885  }
886  return -EIO;
887  }
888 #endif
889  part->bam_cache[blk] = le_virt_addr;
890  }
891  ret = mtd_write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen,
892  (u_char *)&le_virt_addr);
893 
894  if (ret) {
895  printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
896  printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
897  log_addr, virt_addr);
898  }
899  return ret;
900 } /* set_bam_entry */
901 
902 static int ftl_write(partition_t *part, caddr_t buffer,
903  u_long sector, u_long nblocks)
904 {
905  uint32_t bsize, log_addr, virt_addr, old_addr, blk;
906  u_long i;
907  int ret;
908  size_t retlen, offset;
909 
910  pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
911  part, sector, nblocks);
912  if (!(part->state & FTL_FORMATTED)) {
913  printk(KERN_NOTICE "ftl_cs: bad partition\n");
914  return -EIO;
915  }
916  /* See if we need to reclaim space, before we start */
917  while (part->FreeTotal < nblocks) {
918  ret = reclaim_block(part);
919  if (ret)
920  return ret;
921  }
922 
923  bsize = 1 << part->header.EraseUnitSize;
924 
925  virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
926  for (i = 0; i < nblocks; i++) {
927  if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
928  printk(KERN_NOTICE "ftl_cs: bad write offset\n");
929  return -EIO;
930  }
931 
932  /* Grab a free block */
933  blk = find_free(part);
934  if (blk == 0) {
935  static int ne = 0;
936  if (++ne < 5)
937  printk(KERN_NOTICE "ftl_cs: internal error: "
938  "no free blocks!\n");
939  return -ENOSPC;
940  }
941 
942  /* Tag the BAM entry, and write the new block */
943  log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
944  part->EUNInfo[part->bam_index].Free--;
945  part->FreeTotal--;
946  if (set_bam_entry(part, log_addr, 0xfffffffe))
947  return -EIO;
948  part->EUNInfo[part->bam_index].Deleted++;
949  offset = (part->EUNInfo[part->bam_index].Offset +
950  blk * SECTOR_SIZE);
951  ret = mtd_write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer);
952 
953  if (ret) {
954  printk(KERN_NOTICE "ftl_cs: block write failed!\n");
955  printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
956  " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
957  offset);
958  return -EIO;
959  }
960 
961  /* Only delete the old entry when the new entry is ready */
962  old_addr = part->VirtualBlockMap[sector+i];
963  if (old_addr != 0xffffffff) {
964  part->VirtualBlockMap[sector+i] = 0xffffffff;
965  part->EUNInfo[old_addr/bsize].Deleted++;
966  if (set_bam_entry(part, old_addr, 0))
967  return -EIO;
968  }
969 
970  /* Finally, set up the new pointers */
971  if (set_bam_entry(part, log_addr, virt_addr))
972  return -EIO;
973  part->VirtualBlockMap[sector+i] = log_addr;
974  part->EUNInfo[part->bam_index].Deleted--;
975 
976  buffer += SECTOR_SIZE;
977  virt_addr += SECTOR_SIZE;
978  }
979  return 0;
980 } /* ftl_write */
981 
982 static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
983 {
984  partition_t *part = (void *)dev;
985  u_long sect;
986 
987  /* Sort of arbitrary: round size down to 4KiB boundary */
989 
990  geo->heads = 1;
991  geo->sectors = 8;
992  geo->cylinders = sect >> 3;
993 
994  return 0;
995 }
996 
997 static int ftl_readsect(struct mtd_blktrans_dev *dev,
998  unsigned long block, char *buf)
999 {
1000  return ftl_read((void *)dev, buf, block, 1);
1001 }
1002 
1003 static int ftl_writesect(struct mtd_blktrans_dev *dev,
1004  unsigned long block, char *buf)
1005 {
1006  return ftl_write((void *)dev, buf, block, 1);
1007 }
1008 
1009 static int ftl_discardsect(struct mtd_blktrans_dev *dev,
1010  unsigned long sector, unsigned nr_sects)
1011 {
1012  partition_t *part = (void *)dev;
1013  uint32_t bsize = 1 << part->header.EraseUnitSize;
1014 
1015  pr_debug("FTL erase sector %ld for %d sectors\n",
1016  sector, nr_sects);
1017 
1018  while (nr_sects) {
1019  uint32_t old_addr = part->VirtualBlockMap[sector];
1020  if (old_addr != 0xffffffff) {
1021  part->VirtualBlockMap[sector] = 0xffffffff;
1022  part->EUNInfo[old_addr/bsize].Deleted++;
1023  if (set_bam_entry(part, old_addr, 0))
1024  return -EIO;
1025  }
1026  nr_sects--;
1027  sector++;
1028  }
1029 
1030  return 0;
1031 }
1032 /*====================================================================*/
1033 
1034 static void ftl_freepart(partition_t *part)
1035 {
1036  vfree(part->VirtualBlockMap);
1037  part->VirtualBlockMap = NULL;
1038  kfree(part->VirtualPageMap);
1039  part->VirtualPageMap = NULL;
1040  kfree(part->EUNInfo);
1041  part->EUNInfo = NULL;
1042  kfree(part->XferInfo);
1043  part->XferInfo = NULL;
1044  kfree(part->bam_cache);
1045  part->bam_cache = NULL;
1046 } /* ftl_freepart */
1047 
1048 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1049 {
1051 
1052  partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
1053 
1054  if (!partition) {
1055  printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1056  mtd->name);
1057  return;
1058  }
1059 
1060  partition->mbd.mtd = mtd;
1061 
1062  if ((scan_header(partition) == 0) &&
1063  (build_maps(partition) == 0)) {
1064 
1065  partition->state = FTL_FORMATTED;
1066 #ifdef PCMCIA_DEBUG
1067  printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
1068  le32_to_cpu(partition->header.FormattedSize) >> 10);
1069 #endif
1070  partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
1071 
1072  partition->mbd.tr = tr;
1073  partition->mbd.devnum = -1;
1074  if (!add_mtd_blktrans_dev((void *)partition))
1075  return;
1076  }
1077 
1078  ftl_freepart(partition);
1079  kfree(partition);
1080 }
1081 
1082 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
1083 {
1084  del_mtd_blktrans_dev(dev);
1085  ftl_freepart((partition_t *)dev);
1086 }
1087 
1088 static struct mtd_blktrans_ops ftl_tr = {
1089  .name = "ftl",
1090  .major = FTL_MAJOR,
1091  .part_bits = PART_BITS,
1092  .blksize = SECTOR_SIZE,
1093  .readsect = ftl_readsect,
1094  .writesect = ftl_writesect,
1095  .discard = ftl_discardsect,
1096  .getgeo = ftl_getgeo,
1097  .add_mtd = ftl_add_mtd,
1098  .remove_dev = ftl_remove_dev,
1099  .owner = THIS_MODULE,
1100 };
1101 
1102 static int __init init_ftl(void)
1103 {
1104  return register_mtd_blktrans(&ftl_tr);
1105 }
1106 
1107 static void __exit cleanup_ftl(void)
1108 {
1109  deregister_mtd_blktrans(&ftl_tr);
1110 }
1111 
1112 module_init(init_ftl);
1113 module_exit(cleanup_ftl);
1114 
1115 
1116 MODULE_LICENSE("Dual MPL/GPL");
1117 MODULE_AUTHOR("David Hinds <[email protected]>");
1118 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");