~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/mtd/ftl.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
  2  *
  3  * - Based on Id: ftl.c,v 1.21 2000/08/01 13:07:49 dwmw2 Exp
  4  * - With the Franz Galiana's set_bam_entry fix from v1.23
  5  * - Perhaps it's about time I made a branch for the 2.4 series.
  6 
  7  * Originally based on:
  8  */
  9 /*======================================================================
 10 
 11     A Flash Translation Layer memory card driver
 12 
 13     This driver implements a disk-like block device driver with an
 14     apparent block size of 512 bytes for flash memory cards.
 15 
 16     ftl_cs.c 1.62 2000/02/01 00:59:04
 17 
 18     The contents of this file are subject to the Mozilla Public
 19     License Version 1.1 (the "License"); you may not use this file
 20     except in compliance with the License. You may obtain a copy of
 21     the License at http://www.mozilla.org/MPL/
 22 
 23     Software distributed under the License is distributed on an "AS
 24     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 25     implied. See the License for the specific language governing
 26     rights and limitations under the License.
 27 
 28     The initial developer of the original code is David A. Hinds
 29     <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
 30     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 31 
 32     Alternatively, the contents of this file may be used under the
 33     terms of the GNU Public License version 2 (the "GPL"), in which
 34     case the provisions of the GPL are applicable instead of the
 35     above.  If you wish to allow the use of your version of this file
 36     only under the terms of the GPL and not to allow others to use
 37     your version of this file under the MPL, indicate your decision
 38     by deleting the provisions above and replace them with the notice
 39     and other provisions required by the GPL.  If you do not delete
 40     the provisions above, a recipient may use your version of this
 41     file under either the MPL or the GPL.
 42 
 43     LEGAL NOTE: The FTL format is patented by M-Systems.  They have
 44     granted a license for its use with PCMCIA devices:
 45 
 46      "M-Systems grants a royalty-free, non-exclusive license under
 47       any presently existing M-Systems intellectual property rights
 48       necessary for the design and development of FTL-compatible
 49       drivers, file systems and utilities using the data formats with
 50       PCMCIA PC Cards as described in the PCMCIA Flash Translation
 51       Layer (FTL) Specification."
 52 
 53     Use of the FTL format for non-PCMCIA applications may be an
 54     infringement of these patents.  For additional information,
 55     contact M-Systems (http://www.m-sys.com) directly.
 56       
 57 ======================================================================*/
 58 #define FTL_DEBUG 5
 59 #ifdef FTL_DEBUG
 60 #define DEBUGLVL debug
 61 #endif
 62 
 63 #include <linux/module.h>
 64 #include <linux/mtd/compatmac.h>
 65 #include <linux/mtd/mtd.h>
 66 /*#define PSYCHO_DEBUG */
 67 
 68 #include <linux/kernel.h>
 69 #include <linux/sched.h>
 70 #include <linux/ptrace.h>
 71 #include <linux/malloc.h>
 72 #include <linux/string.h>
 73 #include <linux/timer.h>
 74 #include <linux/major.h>
 75 #include <linux/fs.h>
 76 #include <linux/ioctl.h>
 77 #include <linux/hdreg.h>
 78 #include <stdarg.h>
 79 
 80 #if (LINUX_VERSION_CODE >= 0x20100)
 81 #include <linux/vmalloc.h>
 82 #endif
 83 #if (LINUX_VERSION_CODE >= 0x20303)
 84 #include <linux/blkpg.h>
 85 #endif
 86 
 87 #include <linux/mtd/ftl.h>
 88 /*====================================================================*/
 89 /* Stuff which really ought to be in compatmac.h */
 90 
 91 #if (LINUX_VERSION_CODE < 0x20328)
 92 #define register_disk(dev, drive, minors, ops, size) \
 93     do { (dev)->part[(drive)*(minors)].nr_sects = size; \
 94         if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
 95         resetup_one_dev(dev, drive); } while (0);
 96 #endif
 97 
 98 #if (LINUX_VERSION_CODE < 0x20320)
 99 #define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn
100 #define blk_init_queue(q, req)  q = (req)
101 #define blk_cleanup_queue(q)    q = NULL
102 #define request_arg_t           void
103 #else
104 #define request_arg_t           request_queue_t *q
105 #endif
106 
107 
108 /*====================================================================*/
109 
110 /* Parameters that can be set with 'insmod' */
111 
112 /* Major device # for FTL device */
113 static int shuffle_freq = 50;
114 
115 MODULE_PARM(shuffle_freq, "i");
116 
117 /*====================================================================*/
118 
119 #ifndef FTL_MAJOR
120 #define FTL_MAJOR       44
121 #endif
122 
123 
124 /* Funky stuff for setting up a block device */
125 #define MAJOR_NR                FTL_MAJOR
126 #define DEVICE_NAME             "ftl"
127 #define DEVICE_REQUEST          do_ftl_request
128 #define DEVICE_ON(device)
129 #define DEVICE_OFF(device)
130 
131 #define DEVICE_NR(minor)        ((minor)>>5)
132 #define REGION_NR(minor)        (((minor)>>3)&3)
133 #define PART_NR(minor)          ((minor)&7)
134 #define MINOR_NR(dev,reg,part)  (((dev)<<5)+((reg)<<3)+(part))
135 
136 #include <linux/blk.h>
137 
138 #ifdef FTL_DEBUG
139 static int debug = FTL_DEBUG;
140 MODULE_PARM(debug, "i");
141 #endif
142 
143 /*====================================================================*/
144 
145 #ifndef FTL_MAJOR
146 #define FTL_MAJOR       44
147 #endif
148 
149 /* Maximum number of separate memory devices we'll allow */
150 #define MAX_DEV         4
151 
152 /* Maximum number of regions per device */
153 #define MAX_REGION      4
154 
155 /* Maximum number of partitions in an FTL region */
156 #define PART_BITS       3
157 #define MAX_PART        8
158 
159 /* Maximum number of outstanding erase requests per socket */
160 #define MAX_ERASE       8
161 
162 /* Sector size -- shouldn't need to change */
163 #define SECTOR_SIZE     512
164 
165 
166 /* Each memory region corresponds to a minor device */
167 typedef struct partition_t {
168     struct mtd_info     *mtd;
169     u_int32_t           state;
170     u_int32_t           *VirtualBlockMap;
171     u_int32_t           *VirtualPageMap;
172     u_int32_t           FreeTotal;
173     struct eun_info_t {
174         u_int32_t               Offset;
175         u_int32_t               EraseCount;
176         u_int32_t               Free;
177         u_int32_t               Deleted;
178     } *EUNInfo;
179     struct xfer_info_t {
180         u_int32_t               Offset;
181         u_int32_t               EraseCount;
182         u_int16_t               state;
183     } *XferInfo;
184     u_int16_t           bam_index;
185     u_int32_t           *bam_cache;
186     u_int16_t           DataUnits;
187     u_int32_t           BlocksPerUnit;
188     erase_unit_header_t header;
189 #if 0
190     region_info_t       region;
191     memory_handle_t     handle;
192 #endif
193     atomic_t            open;
194 } partition_t;
195 
196 partition_t *myparts[MAX_MTD_DEVICES];
197 
198 static void ftl_notify_add(struct mtd_info *mtd);
199 static void ftl_notify_remove(struct mtd_info *mtd);
200 
201 void ftl_freepart(partition_t *part);
202 
203 static struct mtd_notifier ftl_notifier={ftl_notify_add, ftl_notify_remove, NULL};
204 
205 /* Partition state flags */
206 #define FTL_FORMATTED   0x01
207 
208 /* Transfer unit states */
209 #define XFER_UNKNOWN    0x00
210 #define XFER_ERASING    0x01
211 #define XFER_ERASED     0x02
212 #define XFER_PREPARED   0x03
213 #define XFER_FAILED     0x04
214 
215 static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
216 static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
217 static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
218 
219 static struct gendisk ftl_gendisk = {
220     major:              FTL_MAJOR,
221     major_name:         "ftl",
222     minor_shift:        PART_BITS,
223     max_p:              MAX_PART,
224 #if (LINUX_VERSION_CODE < 0x20328)
225     max_nr:             MAX_DEV*MAX_PART,
226 #endif
227     part:               ftl_hd,
228     sizes:              ftl_sizes,
229     nr_real:            0
230 };
231 
232 /*====================================================================*/
233 
234 static int ftl_ioctl(struct inode *inode, struct file *file,
235                      u_int cmd, u_long arg);
236 static int ftl_open(struct inode *inode, struct file *file);
237 static release_t ftl_close(struct inode *inode, struct file *file);
238 static int ftl_reread_partitions(int minor);
239 
240 static void ftl_erase_callback(struct erase_info *done);
241 
242 #if LINUX_VERSION_CODE < 0x20326
243 static struct file_operations ftl_blk_fops = {
244     open:       ftl_open,
245     release:    ftl_close,
246     ioctl:      ftl_ioctl,
247     read:       block_read,
248     write:      block_write,
249     fsync:      block_fsync
250 };
251 #else
252 static struct block_device_operations ftl_blk_fops = {
253     open:       ftl_open,
254     release:    ftl_close,
255     ioctl:      ftl_ioctl,
256 };
257 #endif
258 
259 /*======================================================================
260 
261     Scan_header() checks to see if a memory region contains an FTL
262     partition.  build_maps() reads all the erase unit headers, builds
263     the erase unit map, and then builds the virtual page map.
264     
265 ======================================================================*/
266 
267 static int scan_header(partition_t *part)
268 {
269     erase_unit_header_t header;
270     loff_t offset, max_offset;
271     int ret;
272     part->header.FormattedSize = 0;
273     max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size;
274     /* Search first megabyte for a valid FTL header */
275     for (offset = 0;
276          offset < max_offset;
277          offset += part->mtd->erasesize?part->mtd->erasesize:0x2000) {
278 
279         ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, 
280                               (unsigned char *)&header);
281         
282         if (ret) 
283             return ret;
284 
285         if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
286     }
287 
288     if (offset == max_offset) {
289         printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
290         return -ENOENT;
291     }
292     if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
293         (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
294         (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
295         printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
296         return -1;
297     }
298     if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
299         printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %lx\n",
300                1 << header.EraseUnitSize,part->mtd->erasesize);
301         return -1;
302     }
303     part->header = header;
304     return 0;
305 }
306 
307 static int build_maps(partition_t *part)
308 {
309     erase_unit_header_t header;
310     u_int16_t xvalid, xtrans, i;
311     u_int blocks, j;
312     int hdr_ok, ret;
313     ssize_t retval;
314     loff_t offset;
315 
316     /* Set up erase unit maps */
317     part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
318         part->header.NumTransferUnits;
319     part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
320                             GFP_KERNEL);
321     if (!part->EUNInfo) return -1;
322     for (i = 0; i < part->DataUnits; i++)
323         part->EUNInfo[i].Offset = 0xffffffff;
324     part->XferInfo =
325         kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
326                 GFP_KERNEL);
327     if (!part->XferInfo) return -1;
328 
329     xvalid = xtrans = 0;
330     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
331         offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
332                       << part->header.EraseUnitSize);
333         ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval, 
334                               (unsigned char *)&header);
335         
336         if (ret) 
337             return ret;
338 
339         /* Is this a transfer partition? */
340         hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
341         if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
342             (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
343             part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
344             part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
345                 le32_to_cpu(header.EraseCount);
346             xvalid++;
347         } else {
348             if (xtrans == part->header.NumTransferUnits) {
349                 printk(KERN_NOTICE "ftl_cs: format error: too many "
350                        "transfer units!\n");
351                 return -1;
352             }
353             if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
354                 part->XferInfo[xtrans].state = XFER_PREPARED;
355                 part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
356             } else {
357                 part->XferInfo[xtrans].state = XFER_UNKNOWN;
358                 /* Pick anything reasonable for the erase count */
359                 part->XferInfo[xtrans].EraseCount =
360                     le32_to_cpu(part->header.EraseCount);
361             }
362             part->XferInfo[xtrans].Offset = offset;
363             xtrans++;
364         }
365     }
366     /* Check for format trouble */
367     header = part->header;
368     if ((xtrans != header.NumTransferUnits) ||
369         (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
370         printk(KERN_NOTICE "ftl_cs: format error: erase units "
371                "don't add up!\n");
372         return -1;
373     }
374     
375     /* Set up virtual page map */
376     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
377     part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
378     memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
379     part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
380 
381     part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
382                               GFP_KERNEL);
383     if (!part->bam_cache) return -1;
384 
385     part->bam_index = 0xffff;
386     part->FreeTotal = 0;
387 
388     for (i = 0; i < part->DataUnits; i++) {
389         part->EUNInfo[i].Free = 0;
390         part->EUNInfo[i].Deleted = 0;
391         offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
392         
393         ret = part->mtd->read(part->mtd, offset,  
394                               part->BlocksPerUnit * sizeof(u_int32_t), &retval, 
395                               (unsigned char *)part->bam_cache);
396         
397         if (ret) 
398             return ret;
399 
400         for (j = 0; j < part->BlocksPerUnit; j++) {
401             if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
402                 part->EUNInfo[i].Free++;
403                 part->FreeTotal++;
404             } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
405                      (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
406                 part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
407                     (i << header.EraseUnitSize) + (j << header.BlockSize);
408             else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
409                 part->EUNInfo[i].Deleted++;
410         }
411     }
412     
413     return 0;
414     
415 } /* build_maps */
416 
417 /*======================================================================
418 
419     Erase_xfer() schedules an asynchronous erase operation for a
420     transfer unit.
421     
422 ======================================================================*/
423 
424 static int erase_xfer(partition_t *part,
425                       u_int16_t xfernum)
426 {
427     int ret;
428     struct xfer_info_t *xfer;
429     struct erase_info *erase;
430 
431     xfer = &part->XferInfo[xfernum];
432     DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
433     xfer->state = XFER_ERASING;
434 
435     /* Is there a free erase slot? Always in MTD. */
436     
437     
438     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
439     if (!erase) 
440             return -ENOMEM;
441 
442     erase->callback = ftl_erase_callback;
443     erase->addr = xfer->Offset;
444     erase->len = 1 << part->header.EraseUnitSize;
445     erase->priv = (u_long)part;
446     
447     ret = part->mtd->erase(part->mtd, erase);
448 
449     if (!ret)
450             xfer->EraseCount++;
451     else
452             kfree(erase);
453 
454     return ret;
455 } /* erase_xfer */
456 
457 /*======================================================================
458 
459     Prepare_xfer() takes a freshly erased transfer unit and gives
460     it an appropriate header.
461     
462 ======================================================================*/
463 
464 static void ftl_erase_callback(struct erase_info *erase)
465 {
466     partition_t *part;
467     struct xfer_info_t *xfer;
468     int i;
469     
470     /* Look up the transfer unit */
471     part = (partition_t *)(erase->priv);
472 
473     for (i = 0; i < part->header.NumTransferUnits; i++)
474         if (part->XferInfo[i].Offset == erase->addr) break;
475 
476     if (i == part->header.NumTransferUnits) {
477         printk(KERN_NOTICE "ftl_cs: internal error: "
478                "erase lookup failed!\n");
479         return;
480     }
481 
482     xfer = &part->XferInfo[i];
483     if (erase->state == MTD_ERASE_DONE)
484         xfer->state = XFER_ERASED;
485     else {
486         xfer->state = XFER_FAILED;
487         printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
488                erase->state);
489     }
490 
491     kfree(erase);
492 
493 } /* ftl_erase_callback */
494 
495 static int prepare_xfer(partition_t *part, int i)
496 {
497     erase_unit_header_t header;
498     struct xfer_info_t *xfer;
499     int nbam, ret;
500     u_int32_t ctl;
501     ssize_t retlen;
502     loff_t offset;
503 
504     xfer = &part->XferInfo[i];
505     xfer->state = XFER_FAILED;
506     
507     DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
508 
509     /* Write the transfer unit header */
510     header = part->header;
511     header.LogicalEUN = cpu_to_le16(0xffff);
512     header.EraseCount = cpu_to_le32(xfer->EraseCount);
513 
514     ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
515                            &retlen, (u_char *)&header);
516 
517     if (ret) {
518         return ret;
519     }
520 
521     /* Write the BAM stub */
522     nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
523             le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
524 
525     offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
526     ctl = cpu_to_le32(BLOCK_CONTROL);
527 
528     for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
529 
530         ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), 
531                                &retlen, (u_char *)&ctl);
532 
533         if (ret)
534             return ret;
535     }
536     xfer->state = XFER_PREPARED;
537     return 0;
538     
539 } /* prepare_xfer */
540 
541 /*======================================================================
542 
543     Copy_erase_unit() takes a full erase block and a transfer unit,
544     copies everything to the transfer unit, then swaps the block
545     pointers.
546 
547     All data blocks are copied to the corresponding blocks in the
548     target unit, so the virtual block map does not need to be
549     updated.
550     
551 ======================================================================*/
552 
553 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
554                            u_int16_t xferunit)
555 {
556     u_char buf[SECTOR_SIZE];
557     struct eun_info_t *eun;
558     struct xfer_info_t *xfer;
559     u_int32_t src, dest, free, i;
560     u_int16_t unit;
561     int ret;
562     ssize_t retlen;
563     loff_t offset;
564     u_int16_t srcunitswap = cpu_to_le16(srcunit);
565 
566     eun = &part->EUNInfo[srcunit];
567     xfer = &part->XferInfo[xferunit];
568     DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
569           eun->Offset, xfer->Offset);
570         
571     
572     /* Read current BAM */
573     if (part->bam_index != srcunit) {
574 
575         offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
576 
577         ret = part->mtd->read(part->mtd, offset, 
578                               part->BlocksPerUnit * sizeof(u_int32_t),
579                               &retlen, (u_char *) (part->bam_cache));
580 
581         /* mark the cache bad, in case we get an error later */
582         part->bam_index = 0xffff;
583 
584         if (ret) {
585             printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");                
586             return ret;
587         }
588     }
589     
590     /* Write the LogicalEUN for the transfer unit */
591     xfer->state = XFER_UNKNOWN;
592     offset = xfer->Offset + 20; /* Bad! */
593     unit = cpu_to_le16(0x7fff);
594 
595     ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
596                            &retlen, (u_char *) &unit);
597     
598     if (ret) {
599         printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
600         return ret;
601     }
602     
603     /* Copy all data blocks from source unit to transfer unit */
604     src = eun->Offset; dest = xfer->Offset;
605 
606     free = 0;
607     ret = 0;
608     for (i = 0; i < part->BlocksPerUnit; i++) {
609         switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
610         case BLOCK_CONTROL:
611             /* This gets updated later */
612             break;
613         case BLOCK_DATA:
614         case BLOCK_REPLACEMENT:
615             ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
616                         &retlen, (u_char *) buf);
617             if (ret) {
618                 printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
619                 return ret;
620             }
621 
622 
623             ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
624                         &retlen, (u_char *) buf);
625             if (ret)  {
626                 printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
627                 return ret;
628             }
629 
630             break;
631         default:
632             /* All other blocks must be free */
633             part->bam_cache[i] = cpu_to_le32(0xffffffff);
634             free++;
635             break;
636         }
637         src += SECTOR_SIZE;
638         dest += SECTOR_SIZE;
639     }
640 
641     /* Write the BAM to the transfer unit */
642     ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), 
643                     part->BlocksPerUnit * sizeof(int32_t), &retlen, 
644                     (u_char *)part->bam_cache);
645     if (ret) {
646         printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
647         return ret;
648     }
649 
650     
651     /* All clear? Then update the LogicalEUN again */
652     ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
653                            &retlen, (u_char *)&srcunitswap);
654 
655     if (ret) {
656         printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
657         return ret;
658     }    
659     
660     
661     /* Update the maps and usage stats*/
662     i = xfer->EraseCount;
663     xfer->EraseCount = eun->EraseCount;
664     eun->EraseCount = i;
665     i = xfer->Offset;
666     xfer->Offset = eun->Offset;
667     eun->Offset = i;
668     part->FreeTotal -= eun->Free;
669     part->FreeTotal += free;
670     eun->Free = free;
671     eun->Deleted = 0;
672     
673     /* Now, the cache should be valid for the new block */
674     part->bam_index = srcunit;
675     
676     return 0;
677 } /* copy_erase_unit */
678 
679 /*======================================================================
680 
681     reclaim_block() picks a full erase unit and a transfer unit and
682     then calls copy_erase_unit() to copy one to the other.  Then, it
683     schedules an erase on the expired block.
684 
685     What's a good way to decide which transfer unit and which erase
686     unit to use?  Beats me.  My way is to always pick the transfer
687     unit with the fewest erases, and usually pick the data unit with
688     the most deleted blocks.  But with a small probability, pick the
689     oldest data unit instead.  This means that we generally postpone
690     the next reclaimation as long as possible, but shuffle static
691     stuff around a bit for wear leveling.
692     
693 ======================================================================*/
694 
695 static int reclaim_block(partition_t *part)
696 {
697     u_int16_t i, eun, xfer;
698     u_int32_t best;
699     int queued, ret;
700 
701     DEBUG(0, "ftl_cs: reclaiming space...\n");
702     DEBUG(4, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
703     /* Pick the least erased transfer unit */
704     best = 0xffffffff; xfer = 0xffff;
705     do {
706         queued = 0;
707         for (i = 0; i < part->header.NumTransferUnits; i++) {
708             int n=0;
709             if (part->XferInfo[i].state == XFER_UNKNOWN) {
710                 DEBUG(4,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
711                 n=1;
712                 erase_xfer(part, i);
713             }
714             if (part->XferInfo[i].state == XFER_ERASING) {
715                 DEBUG(4,"XferInfo[%d].state == XFER_ERASING\n",i);
716                 n=1;
717                 queued = 1;
718             }
719             else if (part->XferInfo[i].state == XFER_ERASED) {
720                 DEBUG(4,"XferInfo[%d].state == XFER_ERASED\n",i);
721                 n=1;
722                 prepare_xfer(part, i);
723             }
724             if (part->XferInfo[i].state == XFER_PREPARED) {
725                 DEBUG(4,"XferInfo[%d].state == XFER_PREPARED\n",i);
726                 n=1;
727                 if (part->XferInfo[i].EraseCount <= best) {
728                     best = part->XferInfo[i].EraseCount;
729                     xfer = i;
730                 }
731             }
732                 if (!n)
733                     DEBUG(4,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
734 
735         }
736         if (xfer == 0xffff) {
737             if (queued) {
738                 DEBUG(1, "ftl_cs: waiting for transfer "
739                       "unit to be prepared...\n");
740                 if (part->mtd->sync)
741                         part->mtd->sync(part->mtd);
742             } else {
743                 static int ne = 0;
744                 if (++ne < 5)
745                     printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
746                            "suitable transfer units!\n");
747                 else
748                     DEBUG(1, "ftl_cs: reclaim failed: no "
749                           "suitable transfer units!\n");
750                         
751                 return -EIO;
752             }
753         }
754     } while (xfer == 0xffff);
755 
756     eun = 0;
757     if ((jiffies % shuffle_freq) == 0) {
758         DEBUG(1, "ftl_cs: recycling freshest block...\n");
759         best = 0xffffffff;
760         for (i = 0; i < part->DataUnits; i++)
761             if (part->EUNInfo[i].EraseCount <= best) {
762                 best = part->EUNInfo[i].EraseCount;
763                 eun = i;
764             }
765     } else {
766         best = 0;
767         for (i = 0; i < part->DataUnits; i++)
768             if (part->EUNInfo[i].Deleted >= best) {
769                 best = part->EUNInfo[i].Deleted;
770                 eun = i;
771             }
772         if (best == 0) {
773             static int ne = 0;
774             if (++ne < 5)
775                 printk(KERN_NOTICE "ftl_cs: reclaim failed: "
776                        "no free blocks!\n");
777             else
778                 DEBUG(1,"ftl_cs: reclaim failed: "
779                        "no free blocks!\n");
780 
781             return -EIO;
782         }
783     }
784     ret = copy_erase_unit(part, eun, xfer);
785     if (!ret)
786         erase_xfer(part, xfer);
787     else
788         printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
789     return ret;
790 } /* reclaim_block */
791 
792 /*======================================================================
793 
794     Find_free() searches for a free block.  If necessary, it updates
795     the BAM cache for the erase unit containing the free block.  It
796     returns the block index -- the erase unit is just the currently
797     cached unit.  If there are no free blocks, it returns 0 -- this
798     is never a valid data block because it contains the header.
799     
800 ======================================================================*/
801 
802 #ifdef PSYCHO_DEBUG
803 static void dump_lists(partition_t *part)
804 {
805     int i;
806     printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
807     for (i = 0; i < part->DataUnits; i++)
808         printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
809                "%d deleted\n", i,
810                part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
811                part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
812 }
813 #endif
814 
815 static u_int32_t find_free(partition_t *part)
816 {
817     u_int16_t stop, eun;
818     u_int32_t blk;
819     size_t retlen;
820     int ret;
821     
822     /* Find an erase unit with some free space */
823     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
824     eun = stop;
825     do {
826         if (part->EUNInfo[eun].Free != 0) break;
827         /* Wrap around at end of table */
828         if (++eun == part->DataUnits) eun = 0;
829     } while (eun != stop);
830 
831     if (part->EUNInfo[eun].Free == 0)
832         return 0;
833     
834     /* Is this unit's BAM cached? */
835     if (eun != part->bam_index) {
836         /* Invalidate cache */
837         part->bam_index = 0xffff;
838 
839         ret = part->mtd->read(part->mtd, 
840                        part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
841                        part->BlocksPerUnit * sizeof(u_int32_t),
842                        &retlen, (u_char *) (part->bam_cache));
843         
844         if (ret) {
845             printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
846             return 0;
847         }
848         part->bam_index = eun;
849     }
850 
851     /* Find a free block */
852     for (blk = 0; blk < part->BlocksPerUnit; blk++)
853         if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
854     if (blk == part->BlocksPerUnit) {
855 #ifdef PSYCHO_DEBUG
856         static int ne = 0;
857         if (++ne == 1)
858             dump_lists(part);
859 #endif
860         printk(KERN_NOTICE "ftl_cs: bad free list!\n");
861         return 0;
862     }
863     DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
864     return blk;
865     
866 } /* find_free */
867 
868 /*======================================================================
869 
870     This gets a memory handle for the region corresponding to the
871     minor device number.
872     
873 ======================================================================*/
874 
875 static int ftl_open(struct inode *inode, struct file *file)
876 {
877     int minor = MINOR(inode->i_rdev);
878     partition_t *partition;
879 
880     if (minor>>4 >= MAX_MTD_DEVICES)
881         return -ENODEV;
882 
883     partition = myparts[minor>>4];
884 
885     if (!partition)
886         return -ENODEV;
887 
888     if (partition->state != FTL_FORMATTED)
889         return -ENXIO;
890     
891     if (ftl_gendisk.part[minor].nr_sects == 0)
892         return -ENXIO;
893 
894     MOD_INC_USE_COUNT;
895 
896     if (!get_mtd_device(partition->mtd, -1)) {
897             MOD_DEC_USE_COUNT;
898             return /* -E'SBUGGEREDOFF */ -ENXIO;
899     }
900     
901     if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
902             put_mtd_device(partition->mtd);
903             MOD_DEC_USE_COUNT;
904             return -EROFS;
905     }
906     
907     DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
908 
909     atomic_inc(&partition->open);
910 
911     return 0;
912 }
913 
914 /*====================================================================*/
915 
916 static release_t ftl_close(struct inode *inode, struct file *file)
917 {
918 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
919     struct super_block *sb = get_super(inode->i_rdev);
920 #endif
921     int minor = MINOR(inode->i_rdev);
922     partition_t *part = myparts[minor >> 4];
923     int i;
924     
925     DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
926 
927     /* Flush all writes */
928     fsync_dev(inode->i_rdev);
929 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
930     if (sb) invalidate_inodes(sb);
931 #endif
932     invalidate_buffers(inode->i_rdev);
933 
934     /* Wait for any pending erase operations to complete */
935     if (part->mtd->sync)
936             part->mtd->sync(part->mtd);
937     
938     for (i = 0; i < part->header.NumTransferUnits; i++) {
939         if (part->XferInfo[i].state == XFER_ERASED)
940             prepare_xfer(part, i);
941     }
942 
943     atomic_dec(&part->open);
944 
945     put_mtd_device(part->mtd);
946     MOD_DEC_USE_COUNT;
947     release_return(0);
948 } /* ftl_close */
949 
950 
951 /*======================================================================
952 
953     Read a series of sectors from an FTL partition.
954     
955 ======================================================================*/
956 
957 static int ftl_read(partition_t *part, caddr_t buffer,
958                     u_long sector, u_long nblocks)
959 {
960     u_int32_t log_addr, bsize;
961     u_long i;
962     int ret;
963     size_t offset, retlen;
964     
965     DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
966           part, sector, nblocks);
967     if (!(part->state & FTL_FORMATTED)) {
968         printk(KERN_NOTICE "ftl_cs: bad partition\n");
969         return -EIO;
970     }
971     bsize = 1 << part->header.EraseUnitSize;
972 
973     for (i = 0; i < nblocks; i++) {
974         if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
975             printk(KERN_NOTICE "ftl_cs: bad read offset\n");
976             return -EIO;
977         }
978         log_addr = part->VirtualBlockMap[sector+i];
979         if (log_addr == 0xffffffff)
980             memset(buffer, 0, SECTOR_SIZE);
981         else {
982             offset = (part->EUNInfo[log_addr / bsize].Offset
983                           + (log_addr % bsize));
984             ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
985                            &retlen, (u_char *) buffer);
986 
987             if (ret) {
988                 printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
989                 return ret;
990             }
991         }
992         buffer += SECTOR_SIZE;
993     }
994     return 0;
995 } /* ftl_read */
996 
997 /*======================================================================
998 
999     Write a series of sectors to an FTL partition
1000     
1001 ======================================================================*/
1002 
1003 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
1004                          u_int32_t virt_addr)
1005 {
1006     u_int32_t bsize, blk, le_virt_addr;
1007 #ifdef PSYCHO_DEBUG
1008     u_int32_t old_addr;
1009 #endif
1010     u_int16_t eun;
1011     int ret;
1012     size_t retlen, offset;
1013 
1014     DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
1015           part, log_addr, virt_addr);
1016     bsize = 1 << part->header.EraseUnitSize;
1017     eun = log_addr / bsize;
1018     blk = (log_addr % bsize) / SECTOR_SIZE;
1019     offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
1020                   le32_to_cpu(part->header.BAMOffset));
1021     
1022 #ifdef PSYCHO_DEBUG
1023     ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
1024                         &retlen, (u_char *)&old_addr);
1025     if (ret) {
1026         printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
1027         return ret;
1028     }
1029     old_addr = le32_to_cpu(old_addr);
1030 
1031     if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
1032         ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
1033         (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
1034         static int ne = 0;
1035         if (++ne < 5) {
1036             printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
1037             printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"
1038                    ", new = 0x%x\n", log_addr, old_addr, virt_addr);
1039         }
1040         return -EIO;
1041     }
1042 #endif
1043     le_virt_addr = cpu_to_le32(virt_addr);
1044     if (part->bam_index == eun) {
1045 #ifdef PSYCHO_DEBUG
1046         if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
1047             static int ne = 0;
1048             if (++ne < 5) {
1049                 printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
1050                        "inconsistency!\n");
1051                 printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"
1052                        " = 0x%x\n",
1053                        le32_to_cpu(part->bam_cache[blk]), old_addr);
1054             }
1055             return -EIO;
1056         }
1057 #endif
1058         part->bam_cache[blk] = le_virt_addr;
1059     }
1060     ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
1061                             &retlen, (u_char *)&le_virt_addr);
1062 
1063     if (ret) {
1064         printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
1065         printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",
1066                log_addr, virt_addr);
1067     }
1068     return ret;
1069 } /* set_bam_entry */
1070 
1071 static int ftl_write(partition_t *part, caddr_t buffer,
1072                      u_long sector, u_long nblocks)
1073 {
1074     u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
1075     u_long i;
1076     int ret;
1077     size_t retlen, offset;
1078 
1079     DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
1080           part, sector, nblocks);
1081     if (!(part->state & FTL_FORMATTED)) {
1082         printk(KERN_NOTICE "ftl_cs: bad partition\n");
1083         return -EIO;
1084     }
1085     /* See if we need to reclaim space, before we start */
1086     while (part->FreeTotal < nblocks) {
1087         ret = reclaim_block(part);
1088         if (ret)
1089             return ret;
1090     }
1091     
1092     bsize = 1 << part->header.EraseUnitSize;
1093 
1094     virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
1095     for (i = 0; i < nblocks; i++) {
1096         if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
1097             printk(KERN_NOTICE "ftl_cs: bad write offset\n");
1098             return -EIO;
1099         }
1100 
1101         /* Grab a free block */
1102         blk = find_free(part);
1103         if (blk == 0) {
1104             static int ne = 0;
1105             if (++ne < 5)
1106                 printk(KERN_NOTICE "ftl_cs: internal error: "
1107                        "no free blocks!\n");
1108             return -ENOSPC;
1109         }
1110 
1111         /* Tag the BAM entry, and write the new block */
1112         log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
1113         part->EUNInfo[part->bam_index].Free--;
1114         part->FreeTotal--;
1115         if (set_bam_entry(part, log_addr, 0xfffffffe)) 
1116             return -EIO;
1117         part->EUNInfo[part->bam_index].Deleted++;
1118         offset = (part->EUNInfo[part->bam_index].Offset +
1119                       blk * SECTOR_SIZE);
1120         ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen, 
1121                                      buffer);
1122 
1123         if (ret) {
1124             printk(KERN_NOTICE "ftl_cs: block write failed!\n");
1125             printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
1126                    " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
1127                    offset);
1128             return -EIO;
1129         }
1130         
1131         /* Only delete the old entry when the new entry is ready */
1132         old_addr = part->VirtualBlockMap[sector+i];
1133         if (old_addr != 0xffffffff) {
1134             part->VirtualBlockMap[sector+i] = 0xffffffff;
1135             part->EUNInfo[old_addr/bsize].Deleted++;
1136             if (set_bam_entry(part, old_addr, 0))
1137                 return -EIO;
1138         }
1139 
1140         /* Finally, set up the new pointers */
1141         if (set_bam_entry(part, log_addr, virt_addr))
1142             return -EIO;
1143         part->VirtualBlockMap[sector+i] = log_addr;
1144         part->EUNInfo[part->bam_index].Deleted--;
1145         
1146         buffer += SECTOR_SIZE;
1147         virt_addr += SECTOR_SIZE;
1148     }
1149     return 0;
1150 } /* ftl_write */
1151 
1152 /*======================================================================
1153 
1154     IOCTL calls for getting device parameters.
1155 
1156 ======================================================================*/
1157 
1158 static int ftl_ioctl(struct inode *inode, struct file *file,
1159                      u_int cmd, u_long arg)
1160 {
1161     struct hd_geometry *geo = (struct hd_geometry *)arg;
1162     int ret = 0, minor = MINOR(inode->i_rdev);
1163     partition_t *part= myparts[minor >> 4];
1164     u_long sect;
1165 
1166     if (!part)
1167         return -ENODEV; /* How? */
1168 
1169     switch (cmd) {
1170     case HDIO_GETGEO:
1171         ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
1172         if (ret) return ret;
1173         /* Sort of arbitrary: round size down to 4K boundary */
1174         sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
1175         put_user(1, (char *)&geo->heads);
1176         put_user(8, (char *)&geo->sectors);
1177         put_user((sect>>3), (short *)&geo->cylinders);
1178         put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
1179         break;
1180     case BLKGETSIZE:
1181         ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(long));
1182         if (ret) return ret;
1183         put_user(ftl_hd[minor].nr_sects, 
1184                  (long *)arg);
1185         break;
1186     case BLKRRPART:
1187         ret = ftl_reread_partitions(minor);
1188         break;
1189 #if (LINUX_VERSION_CODE < 0x20303)
1190     case BLKFLSBUF:
1191 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
1192         if (!capable(CAP_SYS_ADMIN)) return -EACCES;
1193 #endif
1194         fsync_dev(inode->i_rdev);
1195         invalidate_buffers(inode->i_rdev);
1196         break;
1197     RO_IOCTLS(inode->i_rdev, arg);
1198 #else
1199     case BLKROSET:
1200     case BLKROGET:
1201     case BLKFLSBUF:
1202         ret = blk_ioctl(inode->i_rdev, cmd, arg);
1203         break;
1204 #endif
1205     default:
1206         ret = -EINVAL;
1207     }
1208 
1209     return ret;
1210 } /* ftl_ioctl */
1211 
1212 /*======================================================================
1213 
1214     Handler for block device requests
1215 
1216 ======================================================================*/
1217 
1218 static int ftl_reread_partitions(int minor)
1219 {
1220     partition_t *part = myparts[minor >> 4];
1221     int i, whole;
1222 
1223     DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
1224     if ((atomic_read(&part->open) > 1)) {
1225             return -EBUSY;
1226     }
1227     whole = minor & ~(MAX_PART-1);
1228 
1229     for (i = 0; i < MAX_PART; i++) {
1230         if (ftl_hd[whole+i].nr_sects > 0) {
1231             kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);
1232             sync_dev(rdev);
1233             invalidate_buffers(rdev);
1234         }
1235         ftl_hd[whole+i].start_sect = 0;
1236         ftl_hd[whole+i].nr_sects = 0;
1237     }
1238 
1239     scan_header(part);
1240 
1241     register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
1242                   &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
1243 
1244 #ifdef PCMCIA_DEBUG
1245     for (i = 0; i < MAX_PART; i++) {
1246         if (ftl_hd[whole+i].nr_sects > 0)
1247             printk(KERN_INFO "  %d: start %ld size %ld\n", i,
1248                    ftl_hd[whole+i].start_sect,
1249                    ftl_hd[whole+i].nr_sects);
1250     }
1251 #endif
1252     return 0;
1253 }
1254 
1255 /*======================================================================
1256 
1257     Handler for block device requests
1258 
1259 ======================================================================*/
1260 
1261 static void do_ftl_request(request_arg_t)
1262 {
1263     int ret, minor;
1264     partition_t *part;
1265 
1266     do {
1267       //            sti();
1268         INIT_REQUEST;
1269 
1270         minor = MINOR(CURRENT->rq_dev);
1271         
1272         part = myparts[minor >> 4];
1273         if (part) {
1274           ret = 0;
1275           
1276           switch (CURRENT->cmd) {
1277           case READ:
1278             ret = ftl_read(part, CURRENT->buffer,
1279                            CURRENT->sector+ftl_hd[minor].start_sect,
1280                            CURRENT->current_nr_sectors);
1281             if (ret) printk("ftl_read returned %d\n", ret);
1282             break;
1283             
1284           case WRITE:
1285             ret = ftl_write(part, CURRENT->buffer,
1286                             CURRENT->sector+ftl_hd[minor].start_sect,
1287                             CURRENT->current_nr_sectors);
1288             if (ret) printk("ftl_write returned %d\n", ret);
1289             break;
1290             
1291           default:
1292             panic("ftl_cs: unknown block command!\n");
1293             
1294           }
1295         } else {
1296           ret = 1;
1297           printk("NULL part in ftl_request\n");
1298         }
1299          
1300         if (!ret) {
1301           CURRENT->sector += CURRENT->current_nr_sectors;
1302         }
1303         
1304         end_request((ret == 0) ? 1 : 0);
1305     } while (1);
1306 } /* do_ftl_request */
1307 
1308 /*====================================================================*/
1309 
1310 void ftl_freepart(partition_t *part)
1311 {
1312     if (part->VirtualBlockMap) {
1313         vfree(part->VirtualBlockMap);
1314         part->VirtualBlockMap = NULL;
1315     }
1316     if (part->VirtualPageMap) {
1317         kfree(part->VirtualPageMap);
1318         part->VirtualPageMap = NULL;
1319     }
1320     if (part->EUNInfo) {
1321         kfree(part->EUNInfo);
1322         part->EUNInfo = NULL;
1323     }
1324     if (part->XferInfo) {
1325         kfree(part->XferInfo);
1326         part->XferInfo = NULL;
1327     }
1328     if (part->bam_cache) {
1329         kfree(part->bam_cache);
1330         part->bam_cache = NULL;
1331     }
1332     
1333 } /* ftl_freepart */
1334 
1335 static void ftl_notify_add(struct mtd_info *mtd)
1336 {
1337         partition_t *partition;
1338         int device;
1339 
1340         for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
1341                 ;
1342 
1343         if (device == MAX_MTD_DEVICES) {
1344                 printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
1345                        "Not scanning <%s>\n", mtd->name);
1346                 return;
1347         }
1348 
1349         partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
1350                 
1351         if (!partition) {
1352                 printk(KERN_WARNING "No memory to scan for FTL on %s\n",
1353                        mtd->name);
1354                 return;
1355         }    
1356 
1357         memset(partition, 0, sizeof(partition_t));
1358 
1359         partition->mtd = mtd;
1360 
1361         if ((scan_header(partition) == 0) && 
1362             (build_maps(partition) == 0)) {
1363                 
1364                 partition->state = FTL_FORMATTED;
1365                 atomic_set(&partition->open, 0);
1366                 myparts[device] = partition;
1367                 ftl_reread_partitions(device << 4);
1368 #ifdef PCMCIA_DEBUG
1369                 printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
1370                        le32_to_cpu(partition->header.FormattedSize) >> 10);
1371 #endif
1372         }
1373 }
1374 
1375 static void ftl_notify_remove(struct mtd_info *mtd)
1376 {
1377         int i,j;
1378 
1379         /* Q: What happens if you try to remove a device which has
1380          *    a currently-open FTL partition on it?
1381          *
1382          * A: You don't. The ftl_open routine is responsible for
1383          *    increasing the use count of the driver module which
1384          *    it uses.
1385          */
1386 
1387         /* That's the theory, anyway :) */
1388 
1389         for (i=0; i< MAX_MTD_DEVICES; i++)
1390                 if (myparts[i] && myparts[i]->mtd == mtd) {
1391 
1392                         if (myparts[i]->state == FTL_FORMATTED)
1393                                 ftl_freepart(myparts[i]);
1394                         
1395                         myparts[i]->state = 0;
1396                         for (j=0; j<16; j++) {
1397                                 ftl_gendisk.part[j].nr_sects=0;
1398                                 ftl_gendisk.part[j].start_sect=0;
1399                         }
1400                         kfree(myparts[i]);
1401                         myparts[i] = NULL;
1402                 }
1403 }
1404 
1405 
1406 #if LINUX_VERSION_CODE < 0x20300
1407 #ifdef MODULE
1408 #define init_ftl init_module
1409 #define cleanup_ftl cleanup_module
1410 #endif
1411 #endif
1412 
1413 mod_init_t init_ftl(void)
1414 {
1415     int i;
1416 
1417     memset(myparts, 0, sizeof(myparts));
1418     
1419     if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
1420         printk(KERN_NOTICE "ftl_cs: unable to grab major "
1421                "device number!\n");
1422         return -EAGAIN;
1423     }
1424     
1425     for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
1426         ftl_blocksizes[i] = 1024;
1427     for (i = 0; i < MAX_DEV*MAX_PART; i++) {
1428         ftl_hd[i].nr_sects = 0;
1429         ftl_hd[i].start_sect = 0;
1430     }
1431     blksize_size[FTL_MAJOR] = ftl_blocksizes;
1432     ftl_gendisk.major = FTL_MAJOR;
1433     blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
1434     ftl_gendisk.next = gendisk_head;
1435     gendisk_head = &ftl_gendisk;
1436     
1437     register_mtd_user(&ftl_notifier);
1438     
1439     return 0;
1440 }
1441 
1442 mod_exit_t cleanup_ftl(void)
1443 {
1444     struct gendisk *gd, **gdp;
1445 
1446     unregister_mtd_user(&ftl_notifier);
1447 
1448     unregister_blkdev(FTL_MAJOR, "ftl");
1449     blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
1450     blksize_size[FTL_MAJOR] = NULL;
1451 
1452     for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
1453         if (*gdp == &ftl_gendisk) {
1454             gd = *gdp; *gdp = gd->next;
1455             break;
1456         }
1457 }
1458 
1459 #if LINUX_VERSION_CODE > 0x20300
1460 module_init(init_ftl);
1461 module_exit(cleanup_ftl);
1462 #endif
1463 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.