Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");