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