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