fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / mtd / ftl.c
index 4e2d14c..24235d4 100644 (file)
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -53,7 +53,7 @@
     Use of the FTL format for non-PCMCIA applications may be an
     infringement of these patents.  For additional information,
     contact M-Systems (http://www.m-sys.com) directly.
     Use of the FTL format for non-PCMCIA applications may be an
     infringement of these patents.  For additional information,
     contact M-Systems (http://www.m-sys.com) directly.
-      
+
 ======================================================================*/
 #include <linux/mtd/blktrans.h>
 #include <linux/module.h>
 ======================================================================*/
 #include <linux/mtd/blktrans.h>
 #include <linux/module.h>
@@ -80,7 +80,7 @@
 
 /* Parameters that can be set with 'insmod' */
 static int shuffle_freq = 50;
 
 /* Parameters that can be set with 'insmod' */
 static int shuffle_freq = 50;
-MODULE_PARM(shuffle_freq, "i");
+module_param(shuffle_freq, int, 0);
 
 /*====================================================================*/
 
 
 /*====================================================================*/
 
@@ -160,14 +160,15 @@ static void ftl_erase_callback(struct erase_info *done);
     Scan_header() checks to see if a memory region contains an FTL
     partition.  build_maps() reads all the erase unit headers, builds
     the erase unit map, and then builds the virtual page map.
     Scan_header() checks to see if a memory region contains an FTL
     partition.  build_maps() reads all the erase unit headers, builds
     the erase unit map, and then builds the virtual page map.
-    
+
 ======================================================================*/
 
 static int scan_header(partition_t *part)
 {
     erase_unit_header_t header;
     loff_t offset, max_offset;
 ======================================================================*/
 
 static int scan_header(partition_t *part)
 {
     erase_unit_header_t header;
     loff_t offset, max_offset;
-    int ret;
+    size_t ret;
+    int err;
     part->header.FormattedSize = 0;
     max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
     /* Search first megabyte for a valid FTL header */
     part->header.FormattedSize = 0;
     max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
     /* Search first megabyte for a valid FTL header */
@@ -175,11 +176,11 @@ static int scan_header(partition_t *part)
         (offset + sizeof(header)) < max_offset;
         offset += part->mbd.mtd->erasesize ? : 0x2000) {
 
         (offset + sizeof(header)) < max_offset;
         offset += part->mbd.mtd->erasesize ? : 0x2000) {
 
-       ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, 
+       err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
                              (unsigned char *)&header);
                              (unsigned char *)&header);
-       
-       if (ret) 
-           return ret;
+
+       if (err)
+           return err;
 
        if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
     }
 
        if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
     }
@@ -231,10 +232,10 @@ static int build_maps(partition_t *part)
     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
        offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
                      << part->header.EraseUnitSize);
     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
        offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
                      << part->header.EraseUnitSize);
-       ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, 
+       ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
                              (unsigned char *)&header);
                              (unsigned char *)&header);
-       
-       if (ret) 
+
+       if (ret)
            goto out_XferInfo;
 
        ret = -1;
            goto out_XferInfo;
 
        ret = -1;
@@ -273,7 +274,7 @@ static int build_maps(partition_t *part)
               "don't add up!\n");
        goto out_XferInfo;
     }
               "don't add up!\n");
        goto out_XferInfo;
     }
-    
+
     /* Set up virtual page map */
     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
     part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
     /* Set up virtual page map */
     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
     part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
@@ -295,12 +296,12 @@ static int build_maps(partition_t *part)
        part->EUNInfo[i].Free = 0;
        part->EUNInfo[i].Deleted = 0;
        offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
        part->EUNInfo[i].Free = 0;
        part->EUNInfo[i].Deleted = 0;
        offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
-       
-       ret = part->mbd.mtd->read(part->mbd.mtd, offset,  
-                             part->BlocksPerUnit * sizeof(u_int32_t), &retval, 
+
+       ret = part->mbd.mtd->read(part->mbd.mtd, offset,
+                             part->BlocksPerUnit * sizeof(u_int32_t), &retval,
                              (unsigned char *)part->bam_cache);
                              (unsigned char *)part->bam_cache);
-       
-       if (ret) 
+
+       if (ret)
                goto out_bam_cache;
 
        for (j = 0; j < part->BlocksPerUnit; j++) {
                goto out_bam_cache;
 
        for (j = 0; j < part->BlocksPerUnit; j++) {
@@ -315,7 +316,7 @@ static int build_maps(partition_t *part)
                part->EUNInfo[i].Deleted++;
        }
     }
                part->EUNInfo[i].Deleted++;
        }
     }
-    
+
     ret = 0;
     goto out;
 
     ret = 0;
     goto out;
 
@@ -335,7 +336,7 @@ out:
 
     Erase_xfer() schedules an asynchronous erase operation for a
     transfer unit.
 
     Erase_xfer() schedules an asynchronous erase operation for a
     transfer unit.
-    
+
 ======================================================================*/
 
 static int erase_xfer(partition_t *part,
 ======================================================================*/
 
 static int erase_xfer(partition_t *part,
@@ -350,17 +351,18 @@ static int erase_xfer(partition_t *part,
     xfer->state = XFER_ERASING;
 
     /* Is there a free erase slot? Always in MTD. */
     xfer->state = XFER_ERASING;
 
     /* Is there a free erase slot? Always in MTD. */
-    
-    
+
+
     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
-    if (!erase) 
+    if (!erase)
             return -ENOMEM;
 
             return -ENOMEM;
 
+    erase->mtd = part->mbd.mtd;
     erase->callback = ftl_erase_callback;
     erase->addr = xfer->Offset;
     erase->len = 1 << part->header.EraseUnitSize;
     erase->priv = (u_long)part;
     erase->callback = ftl_erase_callback;
     erase->addr = xfer->Offset;
     erase->len = 1 << part->header.EraseUnitSize;
     erase->priv = (u_long)part;
-    
+
     ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
 
     if (!ret)
     ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
 
     if (!ret)
@@ -375,7 +377,7 @@ static int erase_xfer(partition_t *part,
 
     Prepare_xfer() takes a freshly erased transfer unit and gives
     it an appropriate header.
 
     Prepare_xfer() takes a freshly erased transfer unit and gives
     it an appropriate header.
-    
+
 ======================================================================*/
 
 static void ftl_erase_callback(struct erase_info *erase)
 ======================================================================*/
 
 static void ftl_erase_callback(struct erase_info *erase)
@@ -383,7 +385,7 @@ static void ftl_erase_callback(struct erase_info *erase)
     partition_t *part;
     struct xfer_info_t *xfer;
     int i;
     partition_t *part;
     struct xfer_info_t *xfer;
     int i;
-    
+
     /* Look up the transfer unit */
     part = (partition_t *)(erase->priv);
 
     /* Look up the transfer unit */
     part = (partition_t *)(erase->priv);
 
@@ -420,7 +422,7 @@ static int prepare_xfer(partition_t *part, int i)
 
     xfer = &part->XferInfo[i];
     xfer->state = XFER_FAILED;
 
     xfer = &part->XferInfo[i];
     xfer->state = XFER_FAILED;
-    
+
     DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
 
     /* Write the transfer unit header */
     DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
 
     /* Write the transfer unit header */
@@ -444,7 +446,7 @@ static int prepare_xfer(partition_t *part, int i)
 
     for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
 
 
     for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
 
-       ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), 
+       ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
                               &retlen, (u_char *)&ctl);
 
        if (ret)
                               &retlen, (u_char *)&ctl);
 
        if (ret)
@@ -452,7 +454,7 @@ static int prepare_xfer(partition_t *part, int i)
     }
     xfer->state = XFER_PREPARED;
     return 0;
     }
     xfer->state = XFER_PREPARED;
     return 0;
-    
+
 } /* prepare_xfer */
 
 /*======================================================================
 } /* prepare_xfer */
 
 /*======================================================================
@@ -464,7 +466,7 @@ static int prepare_xfer(partition_t *part, int i)
     All data blocks are copied to the corresponding blocks in the
     target unit, so the virtual block map does not need to be
     updated.
     All data blocks are copied to the corresponding blocks in the
     target unit, so the virtual block map does not need to be
     updated.
-    
+
 ======================================================================*/
 
 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
 ======================================================================*/
 
 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
@@ -484,14 +486,14 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     xfer = &part->XferInfo[xferunit];
     DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
          eun->Offset, xfer->Offset);
     xfer = &part->XferInfo[xferunit];
     DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
          eun->Offset, xfer->Offset);
-       
-    
+
+
     /* Read current BAM */
     if (part->bam_index != srcunit) {
 
        offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
 
     /* Read current BAM */
     if (part->bam_index != srcunit) {
 
        offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
 
-       ret = part->mbd.mtd->read(part->mbd.mtd, offset, 
+       ret = part->mbd.mtd->read(part->mbd.mtd, offset,
                              part->BlocksPerUnit * sizeof(u_int32_t),
                              &retlen, (u_char *) (part->bam_cache));
 
                              part->BlocksPerUnit * sizeof(u_int32_t),
                              &retlen, (u_char *) (part->bam_cache));
 
@@ -499,11 +501,11 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
        part->bam_index = 0xffff;
 
        if (ret) {
        part->bam_index = 0xffff;
 
        if (ret) {
-           printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");                
+           printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
            return ret;
        }
     }
            return ret;
        }
     }
-    
+
     /* Write the LogicalEUN for the transfer unit */
     xfer->state = XFER_UNKNOWN;
     offset = xfer->Offset + 20; /* Bad! */
     /* Write the LogicalEUN for the transfer unit */
     xfer->state = XFER_UNKNOWN;
     offset = xfer->Offset + 20; /* Bad! */
@@ -511,12 +513,12 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
 
     ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
                           &retlen, (u_char *) &unit);
 
     ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
                           &retlen, (u_char *) &unit);
-    
+
     if (ret) {
        printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
        return ret;
     }
     if (ret) {
        printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
        return ret;
     }
-    
+
     /* Copy all data blocks from source unit to transfer unit */
     src = eun->Offset; dest = xfer->Offset;
 
     /* Copy all data blocks from source unit to transfer unit */
     src = eun->Offset; dest = xfer->Offset;
 
@@ -556,15 +558,15 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     }
 
     /* Write the BAM to the transfer unit */
     }
 
     /* Write the BAM to the transfer unit */
-    ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), 
-                    part->BlocksPerUnit * sizeof(int32_t), &retlen, 
+    ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
+                    part->BlocksPerUnit * sizeof(int32_t), &retlen,
                    (u_char *)part->bam_cache);
     if (ret) {
        printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
        return ret;
     }
 
                    (u_char *)part->bam_cache);
     if (ret) {
        printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
        return ret;
     }
 
-    
+
     /* All clear? Then update the LogicalEUN again */
     ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
                           &retlen, (u_char *)&srcunitswap);
     /* All clear? Then update the LogicalEUN again */
     ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
                           &retlen, (u_char *)&srcunitswap);
@@ -572,9 +574,9 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     if (ret) {
        printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
        return ret;
     if (ret) {
        printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
        return ret;
-    }    
-    
-    
+    }
+
+
     /* Update the maps and usage stats*/
     i = xfer->EraseCount;
     xfer->EraseCount = eun->EraseCount;
     /* Update the maps and usage stats*/
     i = xfer->EraseCount;
     xfer->EraseCount = eun->EraseCount;
@@ -586,10 +588,10 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     part->FreeTotal += free;
     eun->Free = free;
     eun->Deleted = 0;
     part->FreeTotal += free;
     eun->Free = free;
     eun->Deleted = 0;
-    
+
     /* Now, the cache should be valid for the new block */
     part->bam_index = srcunit;
     /* Now, the cache should be valid for the new block */
     part->bam_index = srcunit;
-    
+
     return 0;
 } /* copy_erase_unit */
 
     return 0;
 } /* copy_erase_unit */
 
@@ -606,7 +608,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     oldest data unit instead.  This means that we generally postpone
     the next reclaimation as long as possible, but shuffle static
     stuff around a bit for wear leveling.
     oldest data unit instead.  This means that we generally postpone
     the next reclaimation as long as possible, but shuffle static
     stuff around a bit for wear leveling.
-    
+
 ======================================================================*/
 
 static int reclaim_block(partition_t *part)
 ======================================================================*/
 
 static int reclaim_block(partition_t *part)
@@ -664,7 +666,7 @@ static int reclaim_block(partition_t *part)
                else
                    DEBUG(1, "ftl_cs: reclaim failed: no "
                          "suitable transfer units!\n");
                else
                    DEBUG(1, "ftl_cs: reclaim failed: no "
                          "suitable transfer units!\n");
-                       
+
                return -EIO;
            }
        }
                return -EIO;
            }
        }
@@ -713,7 +715,7 @@ static int reclaim_block(partition_t *part)
     returns the block index -- the erase unit is just the currently
     cached unit.  If there are no free blocks, it returns 0 -- this
     is never a valid data block because it contains the header.
     returns the block index -- the erase unit is just the currently
     cached unit.  If there are no free blocks, it returns 0 -- this
     is never a valid data block because it contains the header.
-    
+
 ======================================================================*/
 
 #ifdef PSYCHO_DEBUG
 ======================================================================*/
 
 #ifdef PSYCHO_DEBUG
@@ -735,7 +737,7 @@ static u_int32_t find_free(partition_t *part)
     u_int32_t blk;
     size_t retlen;
     int ret;
     u_int32_t blk;
     size_t retlen;
     int ret;
-    
+
     /* Find an erase unit with some free space */
     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
     eun = stop;
     /* Find an erase unit with some free space */
     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
     eun = stop;
@@ -747,17 +749,17 @@ static u_int32_t find_free(partition_t *part)
 
     if (part->EUNInfo[eun].Free == 0)
        return 0;
 
     if (part->EUNInfo[eun].Free == 0)
        return 0;
-    
+
     /* Is this unit's BAM cached? */
     if (eun != part->bam_index) {
        /* Invalidate cache */
        part->bam_index = 0xffff;
 
     /* Is this unit's BAM cached? */
     if (eun != part->bam_index) {
        /* Invalidate cache */
        part->bam_index = 0xffff;
 
-       ret = part->mbd.mtd->read(part->mbd.mtd, 
+       ret = part->mbd.mtd->read(part->mbd.mtd,
                       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
                       part->BlocksPerUnit * sizeof(u_int32_t),
                       &retlen, (u_char *) (part->bam_cache));
                       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
                       part->BlocksPerUnit * sizeof(u_int32_t),
                       &retlen, (u_char *) (part->bam_cache));
-       
+
        if (ret) {
            printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
            return 0;
        if (ret) {
            printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
            return 0;
@@ -779,14 +781,14 @@ static u_int32_t find_free(partition_t *part)
     }
     DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
     return blk;
     }
     DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
     return blk;
-    
+
 } /* find_free */
 
 
 /*======================================================================
 
     Read a series of sectors from an FTL partition.
 } /* find_free */
 
 
 /*======================================================================
 
     Read a series of sectors from an FTL partition.
-    
+
 ======================================================================*/
 
 static int ftl_read(partition_t *part, caddr_t buffer,
 ======================================================================*/
 
 static int ftl_read(partition_t *part, caddr_t buffer,
@@ -796,7 +798,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
     u_long i;
     int ret;
     size_t offset, retlen;
     u_long i;
     int ret;
     size_t offset, retlen;
-    
+
     DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
          part, sector, nblocks);
     if (!(part->state & FTL_FORMATTED)) {
     DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
          part, sector, nblocks);
     if (!(part->state & FTL_FORMATTED)) {
@@ -832,7 +834,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
 /*======================================================================
 
     Write a series of sectors to an FTL partition
 /*======================================================================
 
     Write a series of sectors to an FTL partition
-    
+
 ======================================================================*/
 
 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
 ======================================================================*/
 
 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
@@ -853,7 +855,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
     blk = (log_addr % bsize) / SECTOR_SIZE;
     offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
                  le32_to_cpu(part->header.BAMOffset));
     blk = (log_addr % bsize) / SECTOR_SIZE;
     offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
                  le32_to_cpu(part->header.BAMOffset));
-    
+
 #ifdef PSYCHO_DEBUG
     ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
                         &retlen, (u_char *)&old_addr);
 #ifdef PSYCHO_DEBUG
     ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
                         &retlen, (u_char *)&old_addr);
@@ -923,7 +925,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
        if (ret)
            return ret;
     }
        if (ret)
            return ret;
     }
-    
+
     bsize = 1 << part->header.EraseUnitSize;
 
     virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
     bsize = 1 << part->header.EraseUnitSize;
 
     virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
@@ -947,22 +949,22 @@ static int ftl_write(partition_t *part, caddr_t buffer,
        log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
        part->EUNInfo[part->bam_index].Free--;
        part->FreeTotal--;
        log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
        part->EUNInfo[part->bam_index].Free--;
        part->FreeTotal--;
-       if (set_bam_entry(part, log_addr, 0xfffffffe)) 
+       if (set_bam_entry(part, log_addr, 0xfffffffe))
            return -EIO;
        part->EUNInfo[part->bam_index].Deleted++;
        offset = (part->EUNInfo[part->bam_index].Offset +
                      blk * SECTOR_SIZE);
            return -EIO;
        part->EUNInfo[part->bam_index].Deleted++;
        offset = (part->EUNInfo[part->bam_index].Offset +
                      blk * SECTOR_SIZE);
-       ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, 
+       ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
                                      buffer);
 
        if (ret) {
            printk(KERN_NOTICE "ftl_cs: block write failed!\n");
            printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
                                      buffer);
 
        if (ret) {
            printk(KERN_NOTICE "ftl_cs: block write failed!\n");
            printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
-                  " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
+                  " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
                   offset);
            return -EIO;
        }
                   offset);
            return -EIO;
        }
-       
+
        /* Only delete the old entry when the new entry is ready */
        old_addr = part->VirtualBlockMap[sector+i];
        if (old_addr != 0xffffffff) {
        /* Only delete the old entry when the new entry is ready */
        old_addr = part->VirtualBlockMap[sector+i];
        if (old_addr != 0xffffffff) {
@@ -977,7 +979,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
            return -EIO;
        part->VirtualBlockMap[sector+i] = log_addr;
        part->EUNInfo[part->bam_index].Deleted--;
            return -EIO;
        part->VirtualBlockMap[sector+i] = log_addr;
        part->EUNInfo[part->bam_index].Deleted--;
-       
+
        buffer += SECTOR_SIZE;
        virt_addr += SECTOR_SIZE;
     }
        buffer += SECTOR_SIZE;
        virt_addr += SECTOR_SIZE;
     }
@@ -1015,67 +1017,56 @@ static int ftl_writesect(struct mtd_blktrans_dev *dev,
 
 void ftl_freepart(partition_t *part)
 {
 
 void ftl_freepart(partition_t *part)
 {
-    if (part->VirtualBlockMap) {
        vfree(part->VirtualBlockMap);
        part->VirtualBlockMap = NULL;
        vfree(part->VirtualBlockMap);
        part->VirtualBlockMap = NULL;
-    }
-    if (part->VirtualPageMap) {
        kfree(part->VirtualPageMap);
        part->VirtualPageMap = NULL;
        kfree(part->VirtualPageMap);
        part->VirtualPageMap = NULL;
-    }
-    if (part->EUNInfo) {
        kfree(part->EUNInfo);
        part->EUNInfo = NULL;
        kfree(part->EUNInfo);
        part->EUNInfo = NULL;
-    }
-    if (part->XferInfo) {
        kfree(part->XferInfo);
        part->XferInfo = NULL;
        kfree(part->XferInfo);
        part->XferInfo = NULL;
-    }
-    if (part->bam_cache) {
        kfree(part->bam_cache);
        part->bam_cache = NULL;
        kfree(part->bam_cache);
        part->bam_cache = NULL;
-    }
-    
 } /* ftl_freepart */
 
 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
        partition_t *partition;
 
 } /* ftl_freepart */
 
 static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
        partition_t *partition;
 
-       partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
-               
+       partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
+
        if (!partition) {
                printk(KERN_WARNING "No memory to scan for FTL on %s\n",
                       mtd->name);
                return;
        if (!partition) {
                printk(KERN_WARNING "No memory to scan for FTL on %s\n",
                       mtd->name);
                return;
-       }    
-
-       memset(partition, 0, sizeof(partition_t));
+       }
 
        partition->mbd.mtd = mtd;
 
 
        partition->mbd.mtd = mtd;
 
-       if ((scan_header(partition) == 0) && 
+       if ((scan_header(partition) == 0) &&
            (build_maps(partition) == 0)) {
            (build_maps(partition) == 0)) {
-               
+
                partition->state = FTL_FORMATTED;
 #ifdef PCMCIA_DEBUG
                printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
                       le32_to_cpu(partition->header.FormattedSize) >> 10);
 #endif
                partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
                partition->state = FTL_FORMATTED;
 #ifdef PCMCIA_DEBUG
                printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
                       le32_to_cpu(partition->header.FormattedSize) >> 10);
 #endif
                partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
-               partition->mbd.blksize = SECTOR_SIZE;
+
                partition->mbd.tr = tr;
                partition->mbd.devnum = -1;
                partition->mbd.tr = tr;
                partition->mbd.devnum = -1;
-               if (add_mtd_blktrans_dev((void *)partition))
-                       kfree(partition);
-       
-       } else
-               kfree(partition);
+               if (!add_mtd_blktrans_dev((void *)partition))
+                       return;
+       }
+
+       ftl_freepart(partition);
+       kfree(partition);
 }
 
 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
 {
        del_mtd_blktrans_dev(dev);
 }
 
 static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
 {
        del_mtd_blktrans_dev(dev);
+       ftl_freepart((partition_t *)dev);
        kfree(dev);
 }
 
        kfree(dev);
 }
 
@@ -1083,6 +1074,7 @@ struct mtd_blktrans_ops ftl_tr = {
        .name           = "ftl",
        .major          = FTL_MAJOR,
        .part_bits      = PART_BITS,
        .name           = "ftl",
        .major          = FTL_MAJOR,
        .part_bits      = PART_BITS,
+       .blksize        = SECTOR_SIZE,
        .readsect       = ftl_readsect,
        .writesect      = ftl_writesect,
        .getgeo         = ftl_getgeo,
        .readsect       = ftl_readsect,
        .writesect      = ftl_writesect,
        .getgeo         = ftl_getgeo,
@@ -1091,9 +1083,9 @@ struct mtd_blktrans_ops ftl_tr = {
        .owner          = THIS_MODULE,
 };
 
        .owner          = THIS_MODULE,
 };
 
-int init_ftl(void)
+static int init_ftl(void)
 {
 {
-       DEBUG(0, "$Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $\n");
+       DEBUG(0, "$Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $\n");
 
        return register_mtd_blktrans(&ftl_tr);
 }
 
        return register_mtd_blktrans(&ftl_tr);
 }