[MTD] core: Clean up trailing white spaces
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Родитель
b95f9609c7
Коммит
97894cda57
|
@ -1,4 +1,4 @@
|
||||||
# $Id: Kconfig,v 1.10 2005/07/11 10:39:27 gleixner Exp $
|
# $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $
|
||||||
|
|
||||||
menu "Memory Technology Devices (MTD)"
|
menu "Memory Technology Devices (MTD)"
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ config MTD
|
||||||
will provide the generic support for MTD drivers to register
|
will provide the generic support for MTD drivers to register
|
||||||
themselves with the kernel and for potential users of MTD devices
|
themselves with the kernel and for potential users of MTD devices
|
||||||
to enumerate the devices which are present and obtain a handle on
|
to enumerate the devices which are present and obtain a handle on
|
||||||
them. It will also allow you to select individual drivers for
|
them. It will also allow you to select individual drivers for
|
||||||
particular hardware and users of MTD devices. If unsure, say N.
|
particular hardware and users of MTD devices. If unsure, say N.
|
||||||
|
|
||||||
config MTD_DEBUG
|
config MTD_DEBUG
|
||||||
|
@ -61,11 +61,11 @@ config MTD_REDBOOT_PARTS
|
||||||
|
|
||||||
If you need code which can detect and parse this table, and register
|
If you need code which can detect and parse this table, and register
|
||||||
MTD 'partitions' corresponding to each image in the table, enable
|
MTD 'partitions' corresponding to each image in the table, enable
|
||||||
this option.
|
this option.
|
||||||
|
|
||||||
You will still need the parsing functions to be called by the driver
|
You will still need the parsing functions to be called by the driver
|
||||||
for your particular device. It won't happen automatically. The
|
for your particular device. It won't happen automatically. The
|
||||||
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
|
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
|
||||||
example.
|
example.
|
||||||
|
|
||||||
config MTD_REDBOOT_DIRECTORY_BLOCK
|
config MTD_REDBOOT_DIRECTORY_BLOCK
|
||||||
|
@ -81,10 +81,10 @@ config MTD_REDBOOT_DIRECTORY_BLOCK
|
||||||
partition table. A zero or positive value gives an absolete
|
partition table. A zero or positive value gives an absolete
|
||||||
erase block number. A negative value specifies a number of
|
erase block number. A negative value specifies a number of
|
||||||
sectors before the end of the device.
|
sectors before the end of the device.
|
||||||
|
|
||||||
For example "2" means block number 2, "-1" means the last
|
For example "2" means block number 2, "-1" means the last
|
||||||
block and "-2" means the penultimate block.
|
block and "-2" means the penultimate block.
|
||||||
|
|
||||||
config MTD_REDBOOT_PARTS_UNALLOCATED
|
config MTD_REDBOOT_PARTS_UNALLOCATED
|
||||||
bool " Include unallocated flash regions"
|
bool " Include unallocated flash regions"
|
||||||
depends on MTD_REDBOOT_PARTS
|
depends on MTD_REDBOOT_PARTS
|
||||||
|
@ -105,11 +105,11 @@ config MTD_CMDLINE_PARTS
|
||||||
---help---
|
---help---
|
||||||
Allow generic configuration of the MTD paritition tables via the kernel
|
Allow generic configuration of the MTD paritition tables via the kernel
|
||||||
command line. Multiple flash resources are supported for hardware where
|
command line. Multiple flash resources are supported for hardware where
|
||||||
different kinds of flash memory are available.
|
different kinds of flash memory are available.
|
||||||
|
|
||||||
You will still need the parsing functions to be called by the driver
|
You will still need the parsing functions to be called by the driver
|
||||||
for your particular device. It won't happen automatically. The
|
for your particular device. It won't happen automatically. The
|
||||||
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
|
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
|
||||||
example.
|
example.
|
||||||
|
|
||||||
The format for the command line is as follows:
|
The format for the command line is as follows:
|
||||||
|
@ -118,12 +118,12 @@ config MTD_CMDLINE_PARTS
|
||||||
<mtddef> := <mtd-id>:<partdef>[,<partdef>]
|
<mtddef> := <mtd-id>:<partdef>[,<partdef>]
|
||||||
<partdef> := <size>[@offset][<name>][ro]
|
<partdef> := <size>[@offset][<name>][ro]
|
||||||
<mtd-id> := unique id used in mapping driver/device
|
<mtd-id> := unique id used in mapping driver/device
|
||||||
<size> := standard linux memsize OR "-" to denote all
|
<size> := standard linux memsize OR "-" to denote all
|
||||||
remaining space
|
remaining space
|
||||||
<name> := (NAME)
|
<name> := (NAME)
|
||||||
|
|
||||||
Due to the way Linux handles the command line, no spaces are
|
Due to the way Linux handles the command line, no spaces are
|
||||||
allowed in the partition definition, including mtd id's and partition
|
allowed in the partition definition, including mtd id's and partition
|
||||||
names.
|
names.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
@ -240,7 +240,7 @@ config INFTL
|
||||||
tristate "INFTL (Inverse NAND Flash Translation Layer) support"
|
tristate "INFTL (Inverse NAND Flash Translation Layer) support"
|
||||||
depends on MTD
|
depends on MTD
|
||||||
---help---
|
---help---
|
||||||
This provides support for the Inverse NAND Flash Translation
|
This provides support for the Inverse NAND Flash Translation
|
||||||
Layer which is used on M-Systems' newer DiskOnChip devices. It
|
Layer which is used on M-Systems' newer DiskOnChip devices. It
|
||||||
uses a kind of pseudo-file system on a flash device to emulate
|
uses a kind of pseudo-file system on a flash device to emulate
|
||||||
a block device with 512-byte sectors, on top of which you put
|
a block device with 512-byte sectors, on top of which you put
|
||||||
|
@ -257,8 +257,8 @@ config RFD_FTL
|
||||||
tristate "Resident Flash Disk (Flash Translation Layer) support"
|
tristate "Resident Flash Disk (Flash Translation Layer) support"
|
||||||
depends on MTD
|
depends on MTD
|
||||||
---help---
|
---help---
|
||||||
This provides support for the flash translation layer known
|
This provides support for the flash translation layer known
|
||||||
as the Resident Flash Disk (RFD), as used by the Embedded BIOS
|
as the Resident Flash Disk (RFD), as used by the Embedded BIOS
|
||||||
of General Software. There is a blurb at:
|
of General Software. There is a blurb at:
|
||||||
|
|
||||||
http://www.gensw.com/pages/prod/bios/rfd.htm
|
http://www.gensw.com/pages/prod/bios/rfd.htm
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
/*======================================================================
|
/*======================================================================
|
||||||
|
|
||||||
drivers/mtd/afs.c: ARM Flash Layout/Partitioning
|
drivers/mtd/afs.c: ARM Flash Layout/Partitioning
|
||||||
|
|
||||||
Copyright (C) 2000 ARM Limited
|
Copyright (C) 2000 ARM Limited
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
This is access code for flashes using ARM's flash partitioning
|
This is access code for flashes using ARM's flash partitioning
|
||||||
standards.
|
standards.
|
||||||
|
|
||||||
$Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $
|
$Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_afs_partitions(struct mtd_info *mtd,
|
static int parse_afs_partitions(struct mtd_info *mtd,
|
||||||
struct mtd_partition **pparts,
|
struct mtd_partition **pparts,
|
||||||
unsigned long origin)
|
unsigned long origin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
/*
|
/*
|
||||||
* $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $
|
* $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $
|
||||||
*
|
*
|
||||||
* Read flash partition table from command line
|
* Read flash partition table from command line
|
||||||
*
|
*
|
||||||
* Copyright 2002 SYSGO Real-Time Solutions GmbH
|
* Copyright 2002 SYSGO Real-Time Solutions GmbH
|
||||||
*
|
*
|
||||||
* The format for the command line is as follows:
|
* The format for the command line is as follows:
|
||||||
*
|
*
|
||||||
* mtdparts=<mtddef>[;<mtddef]
|
* mtdparts=<mtddef>[;<mtddef]
|
||||||
* <mtddef> := <mtd-id>:<partdef>[,<partdef>]
|
* <mtddef> := <mtd-id>:<partdef>[,<partdef>]
|
||||||
* <partdef> := <size>[@offset][<name>][ro]
|
* <partdef> := <size>[@offset][<name>][ro]
|
||||||
* <mtd-id> := unique name used in mapping driver/device (mtd->name)
|
* <mtd-id> := unique name used in mapping driver/device (mtd->name)
|
||||||
* <size> := standard linux memsize OR "-" to denote all remaining space
|
* <size> := standard linux memsize OR "-" to denote all remaining space
|
||||||
* <name> := '(' NAME ')'
|
* <name> := '(' NAME ')'
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
* 1 NOR Flash, with 1 single writable partition:
|
* 1 NOR Flash, with 1 single writable partition:
|
||||||
* edb7312-nor:-
|
* edb7312-nor:-
|
||||||
*
|
*
|
||||||
* 1 NOR Flash with 2 partitions, 1 NAND with one
|
* 1 NOR Flash with 2 partitions, 1 NAND with one
|
||||||
* edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
|
* edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
|
||||||
*/
|
*/
|
||||||
|
@ -60,17 +60,17 @@ static int cmdline_parsed = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse one partition definition for an MTD. Since there can be many
|
* Parse one partition definition for an MTD. Since there can be many
|
||||||
* comma separated partition definitions, this function calls itself
|
* comma separated partition definitions, this function calls itself
|
||||||
* recursively until no more partition definitions are found. Nice side
|
* recursively until no more partition definitions are found. Nice side
|
||||||
* effect: the memory to keep the mtd_partition structs and the names
|
* effect: the memory to keep the mtd_partition structs and the names
|
||||||
* is allocated upon the last definition being found. At that point the
|
* is allocated upon the last definition being found. At that point the
|
||||||
* syntax has been verified ok.
|
* syntax has been verified ok.
|
||||||
*/
|
*/
|
||||||
static struct mtd_partition * newpart(char *s,
|
static struct mtd_partition * newpart(char *s,
|
||||||
char **retptr,
|
char **retptr,
|
||||||
int *num_parts,
|
int *num_parts,
|
||||||
int this_part,
|
int this_part,
|
||||||
unsigned char **extra_mem_ptr,
|
unsigned char **extra_mem_ptr,
|
||||||
int extra_mem_size)
|
int extra_mem_size)
|
||||||
{
|
{
|
||||||
struct mtd_partition *parts;
|
struct mtd_partition *parts;
|
||||||
|
@ -102,7 +102,7 @@ static struct mtd_partition * newpart(char *s,
|
||||||
mask_flags = 0; /* this is going to be a regular partition */
|
mask_flags = 0; /* this is going to be a regular partition */
|
||||||
delim = 0;
|
delim = 0;
|
||||||
/* check for offset */
|
/* check for offset */
|
||||||
if (*s == '@')
|
if (*s == '@')
|
||||||
{
|
{
|
||||||
s++;
|
s++;
|
||||||
offset = memparse(s, &s);
|
offset = memparse(s, &s);
|
||||||
|
@ -112,7 +112,7 @@ static struct mtd_partition * newpart(char *s,
|
||||||
{
|
{
|
||||||
delim = ')';
|
delim = ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delim)
|
if (delim)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
@ -131,12 +131,12 @@ static struct mtd_partition * newpart(char *s,
|
||||||
name = NULL;
|
name = NULL;
|
||||||
name_len = 13; /* Partition_000 */
|
name_len = 13; /* Partition_000 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* record name length for memory allocation later */
|
/* record name length for memory allocation later */
|
||||||
extra_mem_size += name_len + 1;
|
extra_mem_size += name_len + 1;
|
||||||
|
|
||||||
/* test for options */
|
/* test for options */
|
||||||
if (strncmp(s, "ro", 2) == 0)
|
if (strncmp(s, "ro", 2) == 0)
|
||||||
{
|
{
|
||||||
mask_flags |= MTD_WRITEABLE;
|
mask_flags |= MTD_WRITEABLE;
|
||||||
s += 2;
|
s += 2;
|
||||||
|
@ -151,7 +151,7 @@ static struct mtd_partition * newpart(char *s,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* more partitions follow, parse them */
|
/* more partitions follow, parse them */
|
||||||
if ((parts = newpart(s + 1, &s, num_parts,
|
if ((parts = newpart(s + 1, &s, num_parts,
|
||||||
this_part + 1, &extra_mem, extra_mem_size)) == 0)
|
this_part + 1, &extra_mem, extra_mem_size)) == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ static struct mtd_partition * newpart(char *s,
|
||||||
extra_mem += name_len + 1;
|
extra_mem += name_len + 1;
|
||||||
|
|
||||||
dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
|
dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
|
||||||
this_part,
|
this_part,
|
||||||
parts[this_part].name,
|
parts[this_part].name,
|
||||||
parts[this_part].offset,
|
parts[this_part].offset,
|
||||||
parts[this_part].size,
|
parts[this_part].size,
|
||||||
|
@ -204,8 +204,8 @@ static struct mtd_partition * newpart(char *s,
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the command line.
|
* Parse the command line.
|
||||||
*/
|
*/
|
||||||
static int mtdpart_setup_real(char *s)
|
static int mtdpart_setup_real(char *s)
|
||||||
{
|
{
|
||||||
|
@ -230,7 +230,7 @@ static int mtdpart_setup_real(char *s)
|
||||||
|
|
||||||
dbg(("parsing <%s>\n", p+1));
|
dbg(("parsing <%s>\n", p+1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse one mtd. have it reserve memory for the
|
* parse one mtd. have it reserve memory for the
|
||||||
* struct cmdline_mtd_partition and the mtd-id string.
|
* struct cmdline_mtd_partition and the mtd-id string.
|
||||||
*/
|
*/
|
||||||
|
@ -239,7 +239,7 @@ static int mtdpart_setup_real(char *s)
|
||||||
&num_parts, /* out: number of parts */
|
&num_parts, /* out: number of parts */
|
||||||
0, /* first partition */
|
0, /* first partition */
|
||||||
(unsigned char**)&this_mtd, /* out: extra mem */
|
(unsigned char**)&this_mtd, /* out: extra mem */
|
||||||
mtd_id_len + 1 + sizeof(*this_mtd) +
|
mtd_id_len + 1 + sizeof(*this_mtd) +
|
||||||
sizeof(void*)-1 /*alignment*/);
|
sizeof(void*)-1 /*alignment*/);
|
||||||
if(!parts)
|
if(!parts)
|
||||||
{
|
{
|
||||||
|
@ -254,21 +254,21 @@ static int mtdpart_setup_real(char *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* align this_mtd */
|
/* align this_mtd */
|
||||||
this_mtd = (struct cmdline_mtd_partition *)
|
this_mtd = (struct cmdline_mtd_partition *)
|
||||||
ALIGN((unsigned long)this_mtd, sizeof(void*));
|
ALIGN((unsigned long)this_mtd, sizeof(void*));
|
||||||
/* enter results */
|
/* enter results */
|
||||||
this_mtd->parts = parts;
|
this_mtd->parts = parts;
|
||||||
this_mtd->num_parts = num_parts;
|
this_mtd->num_parts = num_parts;
|
||||||
this_mtd->mtd_id = (char*)(this_mtd + 1);
|
this_mtd->mtd_id = (char*)(this_mtd + 1);
|
||||||
strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
|
strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
|
||||||
|
|
||||||
/* link into chain */
|
/* link into chain */
|
||||||
this_mtd->next = partitions;
|
this_mtd->next = partitions;
|
||||||
partitions = this_mtd;
|
partitions = this_mtd;
|
||||||
|
|
||||||
dbg(("mtdid=<%s> num_parts=<%d>\n",
|
dbg(("mtdid=<%s> num_parts=<%d>\n",
|
||||||
this_mtd->mtd_id, this_mtd->num_parts));
|
this_mtd->mtd_id, this_mtd->num_parts));
|
||||||
|
|
||||||
|
|
||||||
/* EOS - we're done */
|
/* EOS - we're done */
|
||||||
if (*s == 0)
|
if (*s == 0)
|
||||||
|
@ -292,7 +292,7 @@ static int mtdpart_setup_real(char *s)
|
||||||
* information. It returns partitions for the requested mtd device, or
|
* information. It returns partitions for the requested mtd device, or
|
||||||
* the first one in the chain if a NULL mtd_id is passed in.
|
* the first one in the chain if a NULL mtd_id is passed in.
|
||||||
*/
|
*/
|
||||||
static int parse_cmdline_partitions(struct mtd_info *master,
|
static int parse_cmdline_partitions(struct mtd_info *master,
|
||||||
struct mtd_partition **pparts,
|
struct mtd_partition **pparts,
|
||||||
unsigned long origin)
|
unsigned long origin)
|
||||||
{
|
{
|
||||||
|
@ -322,7 +322,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
|
||||||
part->parts[i].size = master->size - offset;
|
part->parts[i].size = master->size - offset;
|
||||||
if (offset + part->parts[i].size > master->size)
|
if (offset + part->parts[i].size > master->size)
|
||||||
{
|
{
|
||||||
printk(KERN_WARNING ERRP
|
printk(KERN_WARNING ERRP
|
||||||
"%s: partitioning exceeds flash size, truncating\n",
|
"%s: partitioning exceeds flash size, truncating\n",
|
||||||
part->mtd_id);
|
part->mtd_id);
|
||||||
part->parts[i].size = master->size - offset;
|
part->parts[i].size = master->size - offset;
|
||||||
|
@ -338,8 +338,8 @@ static int parse_cmdline_partitions(struct mtd_info *master,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the handler for our kernel parameter, called from
|
* This is the handler for our kernel parameter, called from
|
||||||
* main.c::checksetup(). Note that we can not yet kmalloc() anything,
|
* main.c::checksetup(). Note that we can not yet kmalloc() anything,
|
||||||
* so we only save the commandline for later processing.
|
* so we only save the commandline for later processing.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
|
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
|
||||||
* $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
|
* $Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $
|
||||||
*
|
*
|
||||||
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
||||||
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
|
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
Use of the FTL format for non-PCMCIA applications may be an
|
Use of the FTL format for non-PCMCIA applications may be an
|
||||||
infringement of these patents. For additional information,
|
infringement of these patents. For additional information,
|
||||||
contact M-Systems (http://www.m-sys.com) directly.
|
contact M-Systems (http://www.m-sys.com) directly.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
#include <linux/mtd/blktrans.h>
|
#include <linux/mtd/blktrans.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -160,7 +160,7 @@ static void ftl_erase_callback(struct erase_info *done);
|
||||||
Scan_header() checks to see if a memory region contains an FTL
|
Scan_header() checks to see if a memory region contains an FTL
|
||||||
partition. build_maps() reads all the erase unit headers, builds
|
partition. build_maps() reads all the erase unit headers, builds
|
||||||
the erase unit map, and then builds the virtual page map.
|
the erase unit map, and then builds the virtual page map.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
static int scan_header(partition_t *part)
|
static int scan_header(partition_t *part)
|
||||||
|
@ -176,10 +176,10 @@ static int scan_header(partition_t *part)
|
||||||
(offset + sizeof(header)) < max_offset;
|
(offset + sizeof(header)) < max_offset;
|
||||||
offset += part->mbd.mtd->erasesize ? : 0x2000) {
|
offset += part->mbd.mtd->erasesize ? : 0x2000) {
|
||||||
|
|
||||||
err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
|
err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
|
||||||
(unsigned char *)&header);
|
(unsigned char *)&header);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
|
if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
|
||||||
|
@ -232,10 +232,10 @@ static int build_maps(partition_t *part)
|
||||||
for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
|
for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
|
||||||
offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
|
offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
|
||||||
<< part->header.EraseUnitSize);
|
<< part->header.EraseUnitSize);
|
||||||
ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
|
ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
|
||||||
(unsigned char *)&header);
|
(unsigned char *)&header);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_XferInfo;
|
goto out_XferInfo;
|
||||||
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
@ -274,7 +274,7 @@ static int build_maps(partition_t *part)
|
||||||
"don't add up!\n");
|
"don't add up!\n");
|
||||||
goto out_XferInfo;
|
goto out_XferInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up virtual page map */
|
/* Set up virtual page map */
|
||||||
blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
|
blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
|
||||||
part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
|
part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
|
||||||
|
@ -296,12 +296,12 @@ static int build_maps(partition_t *part)
|
||||||
part->EUNInfo[i].Free = 0;
|
part->EUNInfo[i].Free = 0;
|
||||||
part->EUNInfo[i].Deleted = 0;
|
part->EUNInfo[i].Deleted = 0;
|
||||||
offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
|
offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
|
||||||
|
|
||||||
ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
||||||
part->BlocksPerUnit * sizeof(u_int32_t), &retval,
|
part->BlocksPerUnit * sizeof(u_int32_t), &retval,
|
||||||
(unsigned char *)part->bam_cache);
|
(unsigned char *)part->bam_cache);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_bam_cache;
|
goto out_bam_cache;
|
||||||
|
|
||||||
for (j = 0; j < part->BlocksPerUnit; j++) {
|
for (j = 0; j < part->BlocksPerUnit; j++) {
|
||||||
|
@ -316,7 +316,7 @@ static int build_maps(partition_t *part)
|
||||||
part->EUNInfo[i].Deleted++;
|
part->EUNInfo[i].Deleted++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ out:
|
||||||
|
|
||||||
Erase_xfer() schedules an asynchronous erase operation for a
|
Erase_xfer() schedules an asynchronous erase operation for a
|
||||||
transfer unit.
|
transfer unit.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
static int erase_xfer(partition_t *part,
|
static int erase_xfer(partition_t *part,
|
||||||
|
@ -351,10 +351,10 @@ static int erase_xfer(partition_t *part,
|
||||||
xfer->state = XFER_ERASING;
|
xfer->state = XFER_ERASING;
|
||||||
|
|
||||||
/* Is there a free erase slot? Always in MTD. */
|
/* Is there a free erase slot? Always in MTD. */
|
||||||
|
|
||||||
|
|
||||||
erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
|
erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
|
||||||
if (!erase)
|
if (!erase)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
erase->mtd = part->mbd.mtd;
|
erase->mtd = part->mbd.mtd;
|
||||||
|
@ -362,7 +362,7 @@ static int erase_xfer(partition_t *part,
|
||||||
erase->addr = xfer->Offset;
|
erase->addr = xfer->Offset;
|
||||||
erase->len = 1 << part->header.EraseUnitSize;
|
erase->len = 1 << part->header.EraseUnitSize;
|
||||||
erase->priv = (u_long)part;
|
erase->priv = (u_long)part;
|
||||||
|
|
||||||
ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
|
ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -377,7 +377,7 @@ static int erase_xfer(partition_t *part,
|
||||||
|
|
||||||
Prepare_xfer() takes a freshly erased transfer unit and gives
|
Prepare_xfer() takes a freshly erased transfer unit and gives
|
||||||
it an appropriate header.
|
it an appropriate header.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
static void ftl_erase_callback(struct erase_info *erase)
|
static void ftl_erase_callback(struct erase_info *erase)
|
||||||
|
@ -385,7 +385,7 @@ static void ftl_erase_callback(struct erase_info *erase)
|
||||||
partition_t *part;
|
partition_t *part;
|
||||||
struct xfer_info_t *xfer;
|
struct xfer_info_t *xfer;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Look up the transfer unit */
|
/* Look up the transfer unit */
|
||||||
part = (partition_t *)(erase->priv);
|
part = (partition_t *)(erase->priv);
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ static int prepare_xfer(partition_t *part, int i)
|
||||||
|
|
||||||
xfer = &part->XferInfo[i];
|
xfer = &part->XferInfo[i];
|
||||||
xfer->state = XFER_FAILED;
|
xfer->state = XFER_FAILED;
|
||||||
|
|
||||||
DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
|
DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
|
||||||
|
|
||||||
/* Write the transfer unit header */
|
/* Write the transfer unit header */
|
||||||
|
@ -446,7 +446,7 @@ static int prepare_xfer(partition_t *part, int i)
|
||||||
|
|
||||||
for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
|
for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
|
||||||
|
|
||||||
ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
|
ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
|
||||||
&retlen, (u_char *)&ctl);
|
&retlen, (u_char *)&ctl);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -454,7 +454,7 @@ static int prepare_xfer(partition_t *part, int i)
|
||||||
}
|
}
|
||||||
xfer->state = XFER_PREPARED;
|
xfer->state = XFER_PREPARED;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} /* prepare_xfer */
|
} /* prepare_xfer */
|
||||||
|
|
||||||
/*======================================================================
|
/*======================================================================
|
||||||
|
@ -466,7 +466,7 @@ static int prepare_xfer(partition_t *part, int i)
|
||||||
All data blocks are copied to the corresponding blocks in the
|
All data blocks are copied to the corresponding blocks in the
|
||||||
target unit, so the virtual block map does not need to be
|
target unit, so the virtual block map does not need to be
|
||||||
updated.
|
updated.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
|
@ -486,14 +486,14 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
xfer = &part->XferInfo[xferunit];
|
xfer = &part->XferInfo[xferunit];
|
||||||
DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
|
DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
|
||||||
eun->Offset, xfer->Offset);
|
eun->Offset, xfer->Offset);
|
||||||
|
|
||||||
|
|
||||||
/* Read current BAM */
|
/* Read current BAM */
|
||||||
if (part->bam_index != srcunit) {
|
if (part->bam_index != srcunit) {
|
||||||
|
|
||||||
offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
|
offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
|
||||||
|
|
||||||
ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
ret = part->mbd.mtd->read(part->mbd.mtd, offset,
|
||||||
part->BlocksPerUnit * sizeof(u_int32_t),
|
part->BlocksPerUnit * sizeof(u_int32_t),
|
||||||
&retlen, (u_char *) (part->bam_cache));
|
&retlen, (u_char *) (part->bam_cache));
|
||||||
|
|
||||||
|
@ -501,11 +501,11 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
part->bam_index = 0xffff;
|
part->bam_index = 0xffff;
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
|
printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the LogicalEUN for the transfer unit */
|
/* Write the LogicalEUN for the transfer unit */
|
||||||
xfer->state = XFER_UNKNOWN;
|
xfer->state = XFER_UNKNOWN;
|
||||||
offset = xfer->Offset + 20; /* Bad! */
|
offset = xfer->Offset + 20; /* Bad! */
|
||||||
|
@ -513,12 +513,12 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
|
|
||||||
ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
|
ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
|
||||||
&retlen, (u_char *) &unit);
|
&retlen, (u_char *) &unit);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
|
printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy all data blocks from source unit to transfer unit */
|
/* Copy all data blocks from source unit to transfer unit */
|
||||||
src = eun->Offset; dest = xfer->Offset;
|
src = eun->Offset; dest = xfer->Offset;
|
||||||
|
|
||||||
|
@ -558,15 +558,15 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the BAM to the transfer unit */
|
/* Write the BAM to the transfer unit */
|
||||||
ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
|
ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
|
||||||
part->BlocksPerUnit * sizeof(int32_t), &retlen,
|
part->BlocksPerUnit * sizeof(int32_t), &retlen,
|
||||||
(u_char *)part->bam_cache);
|
(u_char *)part->bam_cache);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
|
printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* All clear? Then update the LogicalEUN again */
|
/* All clear? Then update the LogicalEUN again */
|
||||||
ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
|
ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
|
||||||
&retlen, (u_char *)&srcunitswap);
|
&retlen, (u_char *)&srcunitswap);
|
||||||
|
@ -574,9 +574,9 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
|
printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Update the maps and usage stats*/
|
/* Update the maps and usage stats*/
|
||||||
i = xfer->EraseCount;
|
i = xfer->EraseCount;
|
||||||
xfer->EraseCount = eun->EraseCount;
|
xfer->EraseCount = eun->EraseCount;
|
||||||
|
@ -588,10 +588,10 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
part->FreeTotal += free;
|
part->FreeTotal += free;
|
||||||
eun->Free = free;
|
eun->Free = free;
|
||||||
eun->Deleted = 0;
|
eun->Deleted = 0;
|
||||||
|
|
||||||
/* Now, the cache should be valid for the new block */
|
/* Now, the cache should be valid for the new block */
|
||||||
part->bam_index = srcunit;
|
part->bam_index = srcunit;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* copy_erase_unit */
|
} /* copy_erase_unit */
|
||||||
|
|
||||||
|
@ -608,7 +608,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
|
||||||
oldest data unit instead. This means that we generally postpone
|
oldest data unit instead. This means that we generally postpone
|
||||||
the next reclaimation as long as possible, but shuffle static
|
the next reclaimation as long as possible, but shuffle static
|
||||||
stuff around a bit for wear leveling.
|
stuff around a bit for wear leveling.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
static int reclaim_block(partition_t *part)
|
static int reclaim_block(partition_t *part)
|
||||||
|
@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part)
|
||||||
else
|
else
|
||||||
DEBUG(1, "ftl_cs: reclaim failed: no "
|
DEBUG(1, "ftl_cs: reclaim failed: no "
|
||||||
"suitable transfer units!\n");
|
"suitable transfer units!\n");
|
||||||
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -715,7 +715,7 @@ static int reclaim_block(partition_t *part)
|
||||||
returns the block index -- the erase unit is just the currently
|
returns the block index -- the erase unit is just the currently
|
||||||
cached unit. If there are no free blocks, it returns 0 -- this
|
cached unit. If there are no free blocks, it returns 0 -- this
|
||||||
is never a valid data block because it contains the header.
|
is never a valid data block because it contains the header.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
#ifdef PSYCHO_DEBUG
|
#ifdef PSYCHO_DEBUG
|
||||||
|
@ -737,7 +737,7 @@ static u_int32_t find_free(partition_t *part)
|
||||||
u_int32_t blk;
|
u_int32_t blk;
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Find an erase unit with some free space */
|
/* Find an erase unit with some free space */
|
||||||
stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
|
stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
|
||||||
eun = stop;
|
eun = stop;
|
||||||
|
@ -749,17 +749,17 @@ static u_int32_t find_free(partition_t *part)
|
||||||
|
|
||||||
if (part->EUNInfo[eun].Free == 0)
|
if (part->EUNInfo[eun].Free == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Is this unit's BAM cached? */
|
/* Is this unit's BAM cached? */
|
||||||
if (eun != part->bam_index) {
|
if (eun != part->bam_index) {
|
||||||
/* Invalidate cache */
|
/* Invalidate cache */
|
||||||
part->bam_index = 0xffff;
|
part->bam_index = 0xffff;
|
||||||
|
|
||||||
ret = part->mbd.mtd->read(part->mbd.mtd,
|
ret = part->mbd.mtd->read(part->mbd.mtd,
|
||||||
part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
|
part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
|
||||||
part->BlocksPerUnit * sizeof(u_int32_t),
|
part->BlocksPerUnit * sizeof(u_int32_t),
|
||||||
&retlen, (u_char *) (part->bam_cache));
|
&retlen, (u_char *) (part->bam_cache));
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
|
printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -781,14 +781,14 @@ static u_int32_t find_free(partition_t *part)
|
||||||
}
|
}
|
||||||
DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
|
DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
|
||||||
return blk;
|
return blk;
|
||||||
|
|
||||||
} /* find_free */
|
} /* find_free */
|
||||||
|
|
||||||
|
|
||||||
/*======================================================================
|
/*======================================================================
|
||||||
|
|
||||||
Read a series of sectors from an FTL partition.
|
Read a series of sectors from an FTL partition.
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
static int ftl_read(partition_t *part, caddr_t buffer,
|
static int ftl_read(partition_t *part, caddr_t buffer,
|
||||||
|
@ -798,7 +798,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
|
||||||
u_long i;
|
u_long i;
|
||||||
int ret;
|
int ret;
|
||||||
size_t offset, retlen;
|
size_t offset, retlen;
|
||||||
|
|
||||||
DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
|
DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
|
||||||
part, sector, nblocks);
|
part, sector, nblocks);
|
||||||
if (!(part->state & FTL_FORMATTED)) {
|
if (!(part->state & FTL_FORMATTED)) {
|
||||||
|
@ -834,7 +834,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
|
||||||
/*======================================================================
|
/*======================================================================
|
||||||
|
|
||||||
Write a series of sectors to an FTL partition
|
Write a series of sectors to an FTL partition
|
||||||
|
|
||||||
======================================================================*/
|
======================================================================*/
|
||||||
|
|
||||||
static int set_bam_entry(partition_t *part, u_int32_t log_addr,
|
static int set_bam_entry(partition_t *part, u_int32_t log_addr,
|
||||||
|
@ -855,7 +855,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
|
||||||
blk = (log_addr % bsize) / SECTOR_SIZE;
|
blk = (log_addr % bsize) / SECTOR_SIZE;
|
||||||
offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
|
offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
|
||||||
le32_to_cpu(part->header.BAMOffset));
|
le32_to_cpu(part->header.BAMOffset));
|
||||||
|
|
||||||
#ifdef PSYCHO_DEBUG
|
#ifdef PSYCHO_DEBUG
|
||||||
ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
|
ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
|
||||||
&retlen, (u_char *)&old_addr);
|
&retlen, (u_char *)&old_addr);
|
||||||
|
@ -925,7 +925,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bsize = 1 << part->header.EraseUnitSize;
|
bsize = 1 << part->header.EraseUnitSize;
|
||||||
|
|
||||||
virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
|
virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
|
||||||
|
@ -949,12 +949,12 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
||||||
log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
|
log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
|
||||||
part->EUNInfo[part->bam_index].Free--;
|
part->EUNInfo[part->bam_index].Free--;
|
||||||
part->FreeTotal--;
|
part->FreeTotal--;
|
||||||
if (set_bam_entry(part, log_addr, 0xfffffffe))
|
if (set_bam_entry(part, log_addr, 0xfffffffe))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
part->EUNInfo[part->bam_index].Deleted++;
|
part->EUNInfo[part->bam_index].Deleted++;
|
||||||
offset = (part->EUNInfo[part->bam_index].Offset +
|
offset = (part->EUNInfo[part->bam_index].Offset +
|
||||||
blk * SECTOR_SIZE);
|
blk * SECTOR_SIZE);
|
||||||
ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
|
ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
|
||||||
buffer);
|
buffer);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -964,7 +964,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
||||||
offset);
|
offset);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only delete the old entry when the new entry is ready */
|
/* Only delete the old entry when the new entry is ready */
|
||||||
old_addr = part->VirtualBlockMap[sector+i];
|
old_addr = part->VirtualBlockMap[sector+i];
|
||||||
if (old_addr != 0xffffffff) {
|
if (old_addr != 0xffffffff) {
|
||||||
|
@ -979,7 +979,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
||||||
return -EIO;
|
return -EIO;
|
||||||
part->VirtualBlockMap[sector+i] = log_addr;
|
part->VirtualBlockMap[sector+i] = log_addr;
|
||||||
part->EUNInfo[part->bam_index].Deleted--;
|
part->EUNInfo[part->bam_index].Deleted--;
|
||||||
|
|
||||||
buffer += SECTOR_SIZE;
|
buffer += SECTOR_SIZE;
|
||||||
virt_addr += SECTOR_SIZE;
|
virt_addr += SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -1034,20 +1034,20 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||||
partition_t *partition;
|
partition_t *partition;
|
||||||
|
|
||||||
partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
|
partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
|
||||||
|
|
||||||
if (!partition) {
|
if (!partition) {
|
||||||
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
|
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
|
||||||
mtd->name);
|
mtd->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(partition, 0, sizeof(partition_t));
|
memset(partition, 0, sizeof(partition_t));
|
||||||
|
|
||||||
partition->mbd.mtd = mtd;
|
partition->mbd.mtd = mtd;
|
||||||
|
|
||||||
if ((scan_header(partition) == 0) &&
|
if ((scan_header(partition) == 0) &&
|
||||||
(build_maps(partition) == 0)) {
|
(build_maps(partition) == 0)) {
|
||||||
|
|
||||||
partition->state = FTL_FORMATTED;
|
partition->state = FTL_FORMATTED;
|
||||||
#ifdef PCMCIA_DEBUG
|
#ifdef PCMCIA_DEBUG
|
||||||
printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
|
printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
|
||||||
|
@ -1086,7 +1086,7 @@ struct mtd_blktrans_ops ftl_tr = {
|
||||||
|
|
||||||
int init_ftl(void)
|
int init_ftl(void)
|
||||||
{
|
{
|
||||||
DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
|
DEBUG(0, "$Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $\n");
|
||||||
|
|
||||||
return register_mtd_blktrans(&ftl_tr);
|
return register_mtd_blktrans(&ftl_tr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
|
* inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
|
||||||
*
|
*
|
||||||
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
|
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
|
||||||
|
@ -7,7 +7,7 @@
|
||||||
* (c) 1999 Machine Vision Holdings, Inc.
|
* (c) 1999 Machine Vision Holdings, Inc.
|
||||||
* Author: David Woodhouse <dwmw2@infradead.org>
|
* Author: David Woodhouse <dwmw2@infradead.org>
|
||||||
*
|
*
|
||||||
* $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $
|
* $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -113,14 +113,14 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||||
|
|
||||||
if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
|
if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
|
||||||
/*
|
/*
|
||||||
Oh no we don't have
|
Oh no we don't have
|
||||||
mbd.size == heads * cylinders * sectors
|
mbd.size == heads * cylinders * sectors
|
||||||
*/
|
*/
|
||||||
printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
|
printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
|
||||||
"match size of 0x%lx.\n", inftl->mbd.size);
|
"match size of 0x%lx.\n", inftl->mbd.size);
|
||||||
printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
|
printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
|
||||||
"(== 0x%lx sects)\n",
|
"(== 0x%lx sects)\n",
|
||||||
inftl->cylinders, inftl->heads , inftl->sectors,
|
inftl->cylinders, inftl->heads , inftl->sectors,
|
||||||
(long)inftl->cylinders * (long)inftl->heads *
|
(long)inftl->cylinders * (long)inftl->heads *
|
||||||
(long)inftl->sectors );
|
(long)inftl->sectors );
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
"Virtual Unit Chain %d!\n", thisVUC);
|
"Virtual Unit Chain %d!\n", thisVUC);
|
||||||
return BLOCK_NIL;
|
return BLOCK_NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan to find the Erase Unit which holds the actual data for each
|
* Scan to find the Erase Unit which holds the actual data for each
|
||||||
* 512-byte block within the Chain.
|
* 512-byte block within the Chain.
|
||||||
|
@ -264,7 +264,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
"Unit Chain 0x%x\n", thisVUC);
|
"Unit Chain 0x%x\n", thisVUC);
|
||||||
return BLOCK_NIL;
|
return BLOCK_NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
thisEUN = inftl->PUtable[thisEUN];
|
thisEUN = inftl->PUtable[thisEUN];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,15 +295,15 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
*/
|
*/
|
||||||
if (BlockMap[block] == BLOCK_NIL)
|
if (BlockMap[block] == BLOCK_NIL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
||||||
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
|
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
|
||||||
&retlen, movebuf);
|
&retlen, movebuf);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
|
||||||
BlockMap[block]) + (block * SECTORSIZE),
|
BlockMap[block]) + (block * SECTORSIZE),
|
||||||
SECTORSIZE, &retlen, movebuf);
|
SECTORSIZE, &retlen, movebuf);
|
||||||
if (ret != -EIO)
|
if (ret != -EIO)
|
||||||
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
|
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
|
||||||
"away on retry?\n");
|
"away on retry?\n");
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
||||||
static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
|
static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This is the part that needs some cleverness applied.
|
* This is the part that needs some cleverness applied.
|
||||||
* For now, I'm doing the minimum applicable to actually
|
* For now, I'm doing the minimum applicable to actually
|
||||||
* get the thing to work.
|
* get the thing to work.
|
||||||
* Wear-levelling and other clever stuff needs to be implemented
|
* Wear-levelling and other clever stuff needs to be implemented
|
||||||
|
@ -414,7 +414,7 @@ static int nrbits(unsigned int val, int bitcount)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* INFTL_findwriteunit: Return the unit number into which we can write
|
* INFTL_findwriteunit: Return the unit number into which we can write
|
||||||
* for this block. Make it available if it isn't already.
|
* for this block. Make it available if it isn't already.
|
||||||
*/
|
*/
|
||||||
static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
|
static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
|
||||||
|
@ -463,10 +463,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
|
||||||
* Invalid block. Don't use it any more.
|
* Invalid block. Don't use it any more.
|
||||||
* Must implement.
|
* Must implement.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!silly--) {
|
if (!silly--) {
|
||||||
printk(KERN_WARNING "INFTL: infinite loop in "
|
printk(KERN_WARNING "INFTL: infinite loop in "
|
||||||
"Virtual Unit Chain 0x%x\n", thisVUC);
|
"Virtual Unit Chain 0x%x\n", thisVUC);
|
||||||
return 0xffff;
|
return 0xffff;
|
||||||
|
@ -482,7 +482,7 @@ hitused:
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK. We didn't find one in the existing chain, or there
|
* OK. We didn't find one in the existing chain, or there
|
||||||
* is no existing chain. Allocate a new one.
|
* is no existing chain. Allocate a new one.
|
||||||
*/
|
*/
|
||||||
writeEUN = INFTL_findfreeblock(inftl, 0);
|
writeEUN = INFTL_findfreeblock(inftl, 0);
|
||||||
|
@ -506,8 +506,8 @@ hitused:
|
||||||
if (writeEUN == BLOCK_NIL) {
|
if (writeEUN == BLOCK_NIL) {
|
||||||
/*
|
/*
|
||||||
* Ouch. This should never happen - we should
|
* Ouch. This should never happen - we should
|
||||||
* always be able to make some room somehow.
|
* always be able to make some room somehow.
|
||||||
* If we get here, we've allocated more storage
|
* If we get here, we've allocated more storage
|
||||||
* space than actual media, or our makefreeblock
|
* space than actual media, or our makefreeblock
|
||||||
* routine is missing something.
|
* routine is missing something.
|
||||||
*/
|
*/
|
||||||
|
@ -518,7 +518,7 @@ hitused:
|
||||||
INFTL_dumpVUchains(inftl);
|
INFTL_dumpVUchains(inftl);
|
||||||
#endif
|
#endif
|
||||||
return BLOCK_NIL;
|
return BLOCK_NIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -543,7 +543,7 @@ hitused:
|
||||||
parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
|
parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
|
||||||
parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
|
parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
|
||||||
parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
|
parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
|
||||||
|
|
||||||
oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
|
oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
|
||||||
oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
|
oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
|
||||||
oob.u.a.ANAC = anac;
|
oob.u.a.ANAC = anac;
|
||||||
|
@ -562,7 +562,7 @@ hitused:
|
||||||
oob.u.b.parityPerField = parity;
|
oob.u.b.parityPerField = parity;
|
||||||
oob.u.b.discarded = 0xaa;
|
oob.u.b.discarded = 0xaa;
|
||||||
|
|
||||||
MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
|
MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
|
||||||
SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
|
SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
|
||||||
|
|
||||||
inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
|
inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
|
||||||
|
@ -602,7 +602,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
|
||||||
"Virtual Unit Chain %d!\n", thisVUC);
|
"Virtual Unit Chain %d!\n", thisVUC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan through the Erase Units to determine whether any data is in
|
* Scan through the Erase Units to determine whether any data is in
|
||||||
* each of the 512-byte blocks within the Chain.
|
* each of the 512-byte blocks within the Chain.
|
||||||
|
@ -642,7 +642,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
|
||||||
"Unit Chain 0x%x\n", thisVUC);
|
"Unit Chain 0x%x\n", thisVUC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
thisEUN = inftl->PUtable[thisEUN];
|
thisEUN = inftl->PUtable[thisEUN];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,7 +758,7 @@ foundit:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
||||||
char *buffer)
|
char *buffer)
|
||||||
{
|
{
|
||||||
struct INFTLrecord *inftl = (void *)mbd;
|
struct INFTLrecord *inftl = (void *)mbd;
|
||||||
|
@ -893,7 +893,7 @@ extern char inftlmountrev[];
|
||||||
|
|
||||||
static int __init init_inftl(void)
|
static int __init init_inftl(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, "
|
printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, "
|
||||||
"inftlmount.c %s\n", inftlmountrev);
|
"inftlmount.c %s\n", inftlmountrev);
|
||||||
|
|
||||||
return register_mtd_blktrans(&inftl_tr);
|
return register_mtd_blktrans(&inftl_tr);
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* inftlmount.c -- INFTL mount code with extensive checks.
|
* inftlmount.c -- INFTL mount code with extensive checks.
|
||||||
*
|
*
|
||||||
* Author: Greg Ungerer (gerg@snapgear.com)
|
* Author: Greg Ungerer (gerg@snapgear.com)
|
||||||
* (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com)
|
* (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com)
|
||||||
*
|
*
|
||||||
* Based heavily on the nftlmount.c code which is:
|
* Based heavily on the nftlmount.c code which is:
|
||||||
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
|
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
|
||||||
* Copyright (C) 2000 Netgem S.A.
|
* Copyright (C) 2000 Netgem S.A.
|
||||||
*
|
*
|
||||||
* $Id: inftlmount.c,v 1.17 2005/08/08 08:56:19 dwmw2 Exp $
|
* $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
#include <linux/mtd/inftl.h>
|
#include <linux/mtd/inftl.h>
|
||||||
#include <linux/mtd/compatmac.h>
|
#include <linux/mtd/compatmac.h>
|
||||||
|
|
||||||
char inftlmountrev[]="$Revision: 1.17 $";
|
char inftlmountrev[]="$Revision: 1.18 $";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_boot_record: Find the INFTL Media Header and its Spare copy which
|
* find_boot_record: Find the INFTL Media Header and its Spare copy which
|
||||||
|
@ -273,7 +273,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
|
||||||
inftl->nb_boot_blocks);
|
inftl->nb_boot_blocks);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inftl->mbd.size = inftl->numvunits *
|
inftl->mbd.size = inftl->numvunits *
|
||||||
(inftl->EraseSize / SECTORSIZE);
|
(inftl->EraseSize / SECTORSIZE);
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
|
||||||
inftl->nb_blocks * sizeof(u16));
|
inftl->nb_blocks * sizeof(u16));
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the blocks before INFTL MediaHeader as reserved */
|
/* Mark the blocks before INFTL MediaHeader as reserved */
|
||||||
for (i = 0; i < inftl->nb_boot_blocks; i++)
|
for (i = 0; i < inftl->nb_boot_blocks; i++)
|
||||||
inftl->PUtable[i] = BLOCK_RESERVED;
|
inftl->PUtable[i] = BLOCK_RESERVED;
|
||||||
|
@ -380,7 +380,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
|
||||||
*
|
*
|
||||||
* Return: 0 when succeed, -1 on error.
|
* Return: 0 when succeed, -1 on error.
|
||||||
*
|
*
|
||||||
* ToDo: 1. Is it neceressary to check_free_sector after erasing ??
|
* ToDo: 1. Is it neceressary to check_free_sector after erasing ??
|
||||||
*/
|
*/
|
||||||
int INFTL_formatblock(struct INFTLrecord *inftl, int block)
|
int INFTL_formatblock(struct INFTLrecord *inftl, int block)
|
||||||
{
|
{
|
||||||
|
@ -578,7 +578,7 @@ int INFTL_mount(struct INFTLrecord *s)
|
||||||
printk(KERN_ERR "INFTL: Out of memory.\n");
|
printk(KERN_ERR "INFTL: Out of memory.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(ANACtable, 0, s->nb_blocks);
|
memset(ANACtable, 0, s->nb_blocks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -600,7 +600,7 @@ int INFTL_mount(struct INFTLrecord *s)
|
||||||
|
|
||||||
for (chain_length = 0; ; chain_length++) {
|
for (chain_length = 0; ; chain_length++) {
|
||||||
|
|
||||||
if ((chain_length == 0) &&
|
if ((chain_length == 0) &&
|
||||||
(s->PUtable[block] != BLOCK_NOTEXPLORED)) {
|
(s->PUtable[block] != BLOCK_NOTEXPLORED)) {
|
||||||
/* Nothing to do here, onto next block */
|
/* Nothing to do here, onto next block */
|
||||||
break;
|
break;
|
||||||
|
@ -747,7 +747,7 @@ int INFTL_mount(struct INFTLrecord *s)
|
||||||
"in virtual chain %d\n",
|
"in virtual chain %d\n",
|
||||||
s->PUtable[block], logical_block);
|
s->PUtable[block], logical_block);
|
||||||
s->PUtable[block] = BLOCK_NIL;
|
s->PUtable[block] = BLOCK_NIL;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (ANACtable[block] != ANAC) {
|
if (ANACtable[block] != ANAC) {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $Id: mtd_blkdevs.c,v 1.26 2005/07/29 19:42:04 tpoynor Exp $
|
* $Id: mtd_blkdevs.c,v 1.27 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*
|
*
|
||||||
* (C) 2003 David Woodhouse <dwmw2@infradead.org>
|
* (C) 2003 David Woodhouse <dwmw2@infradead.org>
|
||||||
*
|
*
|
||||||
|
@ -85,7 +85,7 @@ static int mtd_blktrans_thread(void *arg)
|
||||||
daemonize("%sd", tr->name);
|
daemonize("%sd", tr->name);
|
||||||
|
|
||||||
/* daemonize() doesn't do this for us since some kernel threads
|
/* daemonize() doesn't do this for us since some kernel threads
|
||||||
actually want to deal with signals. We can't just call
|
actually want to deal with signals. We can't just call
|
||||||
exit_sighand() since that'll cause an oops when we finally
|
exit_sighand() since that'll cause an oops when we finally
|
||||||
do exit. */
|
do exit. */
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
|
@ -94,7 +94,7 @@ static int mtd_blktrans_thread(void *arg)
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->sighand->siglock);
|
||||||
|
|
||||||
spin_lock_irq(rq->queue_lock);
|
spin_lock_irq(rq->queue_lock);
|
||||||
|
|
||||||
while (!tr->blkcore_priv->exiting) {
|
while (!tr->blkcore_priv->exiting) {
|
||||||
struct request *req;
|
struct request *req;
|
||||||
struct mtd_blktrans_dev *dev;
|
struct mtd_blktrans_dev *dev;
|
||||||
|
@ -157,7 +157,7 @@ static int blktrans_open(struct inode *i, struct file *f)
|
||||||
if (!try_module_get(tr->owner))
|
if (!try_module_get(tr->owner))
|
||||||
goto out_tr;
|
goto out_tr;
|
||||||
|
|
||||||
/* FIXME: Locking. A hot pluggable device can go away
|
/* FIXME: Locking. A hot pluggable device can go away
|
||||||
(del_mtd_device can be called for it) without its module
|
(del_mtd_device can be called for it) without its module
|
||||||
being unloaded. */
|
being unloaded. */
|
||||||
dev->mtd->usecount++;
|
dev->mtd->usecount++;
|
||||||
|
@ -195,7 +195,7 @@ static int blktrans_release(struct inode *i, struct file *f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int blktrans_ioctl(struct inode *inode, struct file *file,
|
static int blktrans_ioctl(struct inode *inode, struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
|
struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
|
||||||
|
@ -264,7 +264,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
|
||||||
/* Required number was free */
|
/* Required number was free */
|
||||||
list_add_tail(&new->list, &d->list);
|
list_add_tail(&new->list, &d->list);
|
||||||
goto added;
|
goto added;
|
||||||
}
|
}
|
||||||
last_devnum = d->devnum;
|
last_devnum = d->devnum;
|
||||||
}
|
}
|
||||||
if (new->devnum == -1)
|
if (new->devnum == -1)
|
||||||
|
@ -288,7 +288,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
|
||||||
gd->major = tr->major;
|
gd->major = tr->major;
|
||||||
gd->first_minor = (new->devnum) << tr->part_bits;
|
gd->first_minor = (new->devnum) << tr->part_bits;
|
||||||
gd->fops = &mtd_blktrans_ops;
|
gd->fops = &mtd_blktrans_ops;
|
||||||
|
|
||||||
if (tr->part_bits)
|
if (tr->part_bits)
|
||||||
if (new->devnum < 26)
|
if (new->devnum < 26)
|
||||||
snprintf(gd->disk_name, sizeof(gd->disk_name),
|
snprintf(gd->disk_name, sizeof(gd->disk_name),
|
||||||
|
@ -314,7 +314,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
|
||||||
set_disk_ro(gd, 1);
|
set_disk_ro(gd, 1);
|
||||||
|
|
||||||
add_disk(gd);
|
add_disk(gd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
|
||||||
|
|
||||||
del_gendisk(old->blkcore_priv);
|
del_gendisk(old->blkcore_priv);
|
||||||
put_disk(old->blkcore_priv);
|
put_disk(old->blkcore_priv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,12 +368,12 @@ static struct mtd_notifier blktrans_notifier = {
|
||||||
.add = blktrans_notify_add,
|
.add = blktrans_notify_add,
|
||||||
.remove = blktrans_notify_remove,
|
.remove = blktrans_notify_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
/* Register the notifier if/when the first device type is
|
/* Register the notifier if/when the first device type is
|
||||||
registered, to prevent the link/init ordering from fucking
|
registered, to prevent the link/init ordering from fucking
|
||||||
us over. */
|
us over. */
|
||||||
if (!blktrans_notifier.list.next)
|
if (!blktrans_notifier.list.next)
|
||||||
|
@ -416,7 +416,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
|
||||||
kfree(tr->blkcore_priv);
|
kfree(tr->blkcore_priv);
|
||||||
up(&mtd_table_mutex);
|
up(&mtd_table_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&tr->devs);
|
INIT_LIST_HEAD(&tr->devs);
|
||||||
list_add(&tr->list, &blktrans_majors);
|
list_add(&tr->list, &blktrans_majors);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Direct MTD block device access
|
* Direct MTD block device access
|
||||||
*
|
*
|
||||||
* $Id: mtdblock.c,v 1.67 2005/11/06 10:04:37 gleixner Exp $
|
* $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*
|
*
|
||||||
* (C) 2000-2003 Nicolas Pitre <nico@cam.org>
|
* (C) 2000-2003 Nicolas Pitre <nico@cam.org>
|
||||||
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
|
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
|
||||||
|
@ -32,7 +32,7 @@ static struct mtdblk_dev {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cache stuff...
|
* Cache stuff...
|
||||||
*
|
*
|
||||||
* Since typical flash erasable sectors are much larger than what Linux's
|
* Since typical flash erasable sectors are much larger than what Linux's
|
||||||
* buffer cache can handle, we must implement read-modify-write on flash
|
* buffer cache can handle, we must implement read-modify-write on flash
|
||||||
* sectors for each block write requests. To avoid over-erasing flash sectors
|
* sectors for each block write requests. To avoid over-erasing flash sectors
|
||||||
|
@ -46,7 +46,7 @@ static void erase_callback(struct erase_info *done)
|
||||||
wake_up(wait_q);
|
wake_up(wait_q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int erase_write (struct mtd_info *mtd, unsigned long pos,
|
static int erase_write (struct mtd_info *mtd, unsigned long pos,
|
||||||
int len, const char *buf)
|
int len, const char *buf)
|
||||||
{
|
{
|
||||||
struct erase_info erase;
|
struct erase_info erase;
|
||||||
|
@ -104,18 +104,18 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
|
DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
|
||||||
"at 0x%lx, size 0x%x\n", mtd->name,
|
"at 0x%lx, size 0x%x\n", mtd->name,
|
||||||
mtdblk->cache_offset, mtdblk->cache_size);
|
mtdblk->cache_offset, mtdblk->cache_size);
|
||||||
|
|
||||||
ret = erase_write (mtd, mtdblk->cache_offset,
|
ret = erase_write (mtd, mtdblk->cache_offset,
|
||||||
mtdblk->cache_size, mtdblk->cache_data);
|
mtdblk->cache_size, mtdblk->cache_data);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we could argubly set the cache state to STATE_CLEAN.
|
* Here we could argubly set the cache state to STATE_CLEAN.
|
||||||
* However this could lead to inconsistency since we will not
|
* However this could lead to inconsistency since we will not
|
||||||
* be notified if this content is altered on the flash by other
|
* be notified if this content is altered on the flash by other
|
||||||
* means. Let's declare it empty and leave buffering tasks to
|
* means. Let's declare it empty and leave buffering tasks to
|
||||||
* the buffer cache instead.
|
* the buffer cache instead.
|
||||||
*/
|
*/
|
||||||
|
@ -124,7 +124,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
int len, const char *buf)
|
int len, const char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = mtdblk->mtd;
|
struct mtd_info *mtd = mtdblk->mtd;
|
||||||
|
@ -134,7 +134,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
|
DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
|
||||||
mtd->name, pos, len);
|
mtd->name, pos, len);
|
||||||
|
|
||||||
if (!sect_size)
|
if (!sect_size)
|
||||||
return MTD_WRITE (mtd, pos, len, &retlen, buf);
|
return MTD_WRITE (mtd, pos, len, &retlen, buf);
|
||||||
|
|
||||||
|
@ -142,11 +142,11 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
unsigned long sect_start = (pos/sect_size)*sect_size;
|
unsigned long sect_start = (pos/sect_size)*sect_size;
|
||||||
unsigned int offset = pos - sect_start;
|
unsigned int offset = pos - sect_start;
|
||||||
unsigned int size = sect_size - offset;
|
unsigned int size = sect_size - offset;
|
||||||
if( size > len )
|
if( size > len )
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
if (size == sect_size) {
|
if (size == sect_size) {
|
||||||
/*
|
/*
|
||||||
* We are covering a whole sector. Thus there is no
|
* We are covering a whole sector. Thus there is no
|
||||||
* need to bother with the cache while it may still be
|
* need to bother with the cache while it may still be
|
||||||
* useful for other partial writes.
|
* useful for other partial writes.
|
||||||
|
@ -160,7 +160,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
if (mtdblk->cache_state == STATE_DIRTY &&
|
if (mtdblk->cache_state == STATE_DIRTY &&
|
||||||
mtdblk->cache_offset != sect_start) {
|
mtdblk->cache_offset != sect_start) {
|
||||||
ret = write_cached_data(mtdblk);
|
ret = write_cached_data(mtdblk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
|
static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
int len, char *buf)
|
int len, char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = mtdblk->mtd;
|
struct mtd_info *mtd = mtdblk->mtd;
|
||||||
|
@ -201,9 +201,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
|
DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
|
||||||
mtd->name, pos, len);
|
mtd->name, pos, len);
|
||||||
|
|
||||||
if (!sect_size)
|
if (!sect_size)
|
||||||
return MTD_READ (mtd, pos, len, &retlen, buf);
|
return MTD_READ (mtd, pos, len, &retlen, buf);
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||||
unsigned long sect_start = (pos/sect_size)*sect_size;
|
unsigned long sect_start = (pos/sect_size)*sect_size;
|
||||||
unsigned int offset = pos - sect_start;
|
unsigned int offset = pos - sect_start;
|
||||||
unsigned int size = sect_size - offset;
|
unsigned int size = sect_size - offset;
|
||||||
if (size > len)
|
if (size > len)
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -269,12 +269,12 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
|
||||||
int dev = mbd->devnum;
|
int dev = mbd->devnum;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
|
DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
|
||||||
|
|
||||||
if (mtdblks[dev]) {
|
if (mtdblks[dev]) {
|
||||||
mtdblks[dev]->count++;
|
mtdblks[dev]->count++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK, it's not open. Create cache info for it */
|
/* OK, it's not open. Create cache info for it */
|
||||||
mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
|
mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
|
||||||
if (!mtdblk)
|
if (!mtdblk)
|
||||||
|
@ -293,7 +293,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
|
||||||
}
|
}
|
||||||
|
|
||||||
mtdblks[dev] = mtdblk;
|
mtdblks[dev] = mtdblk;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
|
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -321,7 +321,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
|
||||||
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
|
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mtdblock_flush(struct mtd_blktrans_dev *dev)
|
static int mtdblock_flush(struct mtd_blktrans_dev *dev)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $Id: mtdchar.c,v 1.75 2005/11/06 10:04:37 gleixner Exp $
|
* $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*
|
*
|
||||||
* Character-device access to raw MTD devices.
|
* Character-device access to raw MTD devices.
|
||||||
*
|
*
|
||||||
|
@ -28,7 +28,7 @@ static void mtd_notify_add(struct mtd_info* mtd)
|
||||||
|
|
||||||
class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
|
class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
|
||||||
NULL, "mtd%d", mtd->index);
|
NULL, "mtd%d", mtd->index);
|
||||||
|
|
||||||
class_device_create(mtd_class, NULL,
|
class_device_create(mtd_class, NULL,
|
||||||
MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
|
MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
|
||||||
NULL, "mtd%dro", mtd->index);
|
NULL, "mtd%dro", mtd->index);
|
||||||
|
@ -108,23 +108,23 @@ static int mtd_open(struct inode *inode, struct file *file)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
mtd = get_mtd_device(NULL, devnum);
|
mtd = get_mtd_device(NULL, devnum);
|
||||||
|
|
||||||
if (!mtd)
|
if (!mtd)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (MTD_ABSENT == mtd->type) {
|
if (MTD_ABSENT == mtd->type) {
|
||||||
put_mtd_device(mtd);
|
put_mtd_device(mtd);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->private_data = mtd;
|
file->private_data = mtd;
|
||||||
|
|
||||||
/* You can't open it RW if it's not a writeable device */
|
/* You can't open it RW if it's not a writeable device */
|
||||||
if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
|
if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
|
||||||
put_mtd_device(mtd);
|
put_mtd_device(mtd);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* mtd_open */
|
} /* mtd_open */
|
||||||
|
|
||||||
|
@ -137,10 +137,10 @@ static int mtd_close(struct inode *inode, struct file *file)
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
|
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
|
||||||
|
|
||||||
mtd = TO_MTD(file);
|
mtd = TO_MTD(file);
|
||||||
|
|
||||||
if (mtd->sync)
|
if (mtd->sync)
|
||||||
mtd->sync(mtd);
|
mtd->sync(mtd);
|
||||||
|
|
||||||
put_mtd_device(mtd);
|
put_mtd_device(mtd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -159,7 +159,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
|
||||||
int ret=0;
|
int ret=0;
|
||||||
int len;
|
int len;
|
||||||
char *kbuf;
|
char *kbuf;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
|
DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
|
||||||
|
|
||||||
if (*ppos + count > mtd->size)
|
if (*ppos + count > mtd->size)
|
||||||
|
@ -167,11 +167,11 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* FIXME: Use kiovec in 2.5 to lock down the user's buffers
|
/* FIXME: Use kiovec in 2.5 to lock down the user's buffers
|
||||||
and pass them directly to the MTD functions */
|
and pass them directly to the MTD functions */
|
||||||
while (count) {
|
while (count) {
|
||||||
if (count > MAX_KMALLOC_SIZE)
|
if (count > MAX_KMALLOC_SIZE)
|
||||||
len = MAX_KMALLOC_SIZE;
|
len = MAX_KMALLOC_SIZE;
|
||||||
else
|
else
|
||||||
len = count;
|
len = count;
|
||||||
|
@ -179,7 +179,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
|
||||||
kbuf=kmalloc(len,GFP_KERNEL);
|
kbuf=kmalloc(len,GFP_KERNEL);
|
||||||
if (!kbuf)
|
if (!kbuf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
switch (MTD_MODE(file)) {
|
switch (MTD_MODE(file)) {
|
||||||
case MTD_MODE_OTP_FACT:
|
case MTD_MODE_OTP_FACT:
|
||||||
ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
|
ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
|
||||||
|
@ -192,7 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
|
||||||
}
|
}
|
||||||
/* Nand returns -EBADMSG on ecc errors, but it returns
|
/* Nand returns -EBADMSG on ecc errors, but it returns
|
||||||
* the data. For our userspace tools it is important
|
* the data. For our userspace tools it is important
|
||||||
* to dump areas with ecc errors !
|
* to dump areas with ecc errors !
|
||||||
* Userspace software which accesses NAND this way
|
* Userspace software which accesses NAND this way
|
||||||
* must be aware of the fact that it deals with NAND
|
* must be aware of the fact that it deals with NAND
|
||||||
*/
|
*/
|
||||||
|
@ -214,7 +214,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
|
||||||
kfree(kbuf);
|
kfree(kbuf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(kbuf);
|
kfree(kbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,10 +231,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
|
DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
|
||||||
|
|
||||||
if (*ppos == mtd->size)
|
if (*ppos == mtd->size)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
if (*ppos + count > mtd->size)
|
if (*ppos + count > mtd->size)
|
||||||
count = mtd->size - *ppos;
|
count = mtd->size - *ppos;
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
if (count > MAX_KMALLOC_SIZE)
|
if (count > MAX_KMALLOC_SIZE)
|
||||||
len = MAX_KMALLOC_SIZE;
|
len = MAX_KMALLOC_SIZE;
|
||||||
else
|
else
|
||||||
len = count;
|
len = count;
|
||||||
|
@ -257,7 +257,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
|
||||||
kfree(kbuf);
|
kfree(kbuf);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (MTD_MODE(file)) {
|
switch (MTD_MODE(file)) {
|
||||||
case MTD_MODE_OTP_FACT:
|
case MTD_MODE_OTP_FACT:
|
||||||
ret = -EROFS;
|
ret = -EROFS;
|
||||||
|
@ -282,7 +282,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
|
||||||
kfree(kbuf);
|
kfree(kbuf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(kbuf);
|
kfree(kbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u_long size;
|
u_long size;
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
|
DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
|
||||||
|
|
||||||
size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
|
size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
|
||||||
|
@ -318,7 +318,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
if (!access_ok(VERIFY_WRITE, argp, size))
|
if (!access_ok(VERIFY_WRITE, argp, size))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case MEMGETREGIONCOUNT:
|
case MEMGETREGIONCOUNT:
|
||||||
if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
|
if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
|
||||||
|
@ -370,11 +370,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
erase->mtd = mtd;
|
erase->mtd = mtd;
|
||||||
erase->callback = mtdchar_erase_callback;
|
erase->callback = mtdchar_erase_callback;
|
||||||
erase->priv = (unsigned long)&waitq;
|
erase->priv = (unsigned long)&waitq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FIXME: Allow INTERRUPTIBLE. Which means
|
FIXME: Allow INTERRUPTIBLE. Which means
|
||||||
not having the wait_queue head on the stack.
|
not having the wait_queue head on the stack.
|
||||||
|
|
||||||
If the wq_head is on the stack, and we
|
If the wq_head is on the stack, and we
|
||||||
leave because we got interrupted, then the
|
leave because we got interrupted, then the
|
||||||
wq_head is no longer there when the
|
wq_head is no longer there when the
|
||||||
|
@ -402,13 +402,13 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
struct mtd_oob_buf buf;
|
struct mtd_oob_buf buf;
|
||||||
void *databuf;
|
void *databuf;
|
||||||
ssize_t retlen;
|
ssize_t retlen;
|
||||||
|
|
||||||
if(!(file->f_mode & 2))
|
if(!(file->f_mode & 2))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
|
if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (buf.length > 0x4096)
|
if (buf.length > 0x4096)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -424,7 +424,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
databuf = kmalloc(buf.length, GFP_KERNEL);
|
databuf = kmalloc(buf.length, GFP_KERNEL);
|
||||||
if (!databuf)
|
if (!databuf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (copy_from_user(databuf, buf.ptr, buf.length)) {
|
if (copy_from_user(databuf, buf.ptr, buf.length)) {
|
||||||
kfree(databuf);
|
kfree(databuf);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -448,7 +448,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
|
|
||||||
if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
|
if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (buf.length > 0x4096)
|
if (buf.length > 0x4096)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -464,14 +464,14 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
databuf = kmalloc(buf.length, GFP_KERNEL);
|
databuf = kmalloc(buf.length, GFP_KERNEL);
|
||||||
if (!databuf)
|
if (!databuf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
|
ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
|
||||||
|
|
||||||
if (put_user(retlen, (uint32_t __user *)argp))
|
if (put_user(retlen, (uint32_t __user *)argp))
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
|
else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
|
|
||||||
kfree(databuf);
|
kfree(databuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -521,7 +521,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
|
||||||
case MEMGETBADBLOCK:
|
case MEMGETBADBLOCK:
|
||||||
{
|
{
|
||||||
loff_t offs;
|
loff_t offs;
|
||||||
|
|
||||||
if (copy_from_user(&offs, argp, sizeof(loff_t)))
|
if (copy_from_user(&offs, argp, sizeof(loff_t)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (!mtd->block_isbad)
|
if (!mtd->block_isbad)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
* This code is GPL
|
* This code is GPL
|
||||||
*
|
*
|
||||||
* $Id: mtdconcat.c,v 1.10 2005/11/06 10:04:37 gleixner Exp $
|
* $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -44,7 +44,7 @@ struct mtd_concat {
|
||||||
*/
|
*/
|
||||||
#define CONCAT(x) ((struct mtd_concat *)(x))
|
#define CONCAT(x) ((struct mtd_concat *)(x))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MTD methods which look up the relevant subdevice, translate the
|
* MTD methods which look up the relevant subdevice, translate the
|
||||||
* effective address and pass through to the subdevice.
|
* effective address and pass through to the subdevice.
|
||||||
*/
|
*/
|
||||||
|
@ -878,7 +878,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||||
return &concat->mtd;
|
return &concat->mtd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function destroys an MTD object obtained from concat_mtd_devs()
|
* This function destroys an MTD object obtained from concat_mtd_devs()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $Id: mtdcore.c,v 1.46 2005/08/11 17:13:43 gleixner Exp $
|
* $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*
|
*
|
||||||
* Core registration and callback routines for MTD
|
* Core registration and callback routines for MTD
|
||||||
* drivers and users.
|
* drivers and users.
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
|
|
||||||
/* These are exported solely for the purpose of mtd_blkdevs.c. You
|
/* These are exported solely for the purpose of mtd_blkdevs.c. You
|
||||||
should not use them for _anything_ else */
|
should not use them for _anything_ else */
|
||||||
DECLARE_MUTEX(mtd_table_mutex);
|
DECLARE_MUTEX(mtd_table_mutex);
|
||||||
struct mtd_info *mtd_table[MAX_MTD_DEVICES];
|
struct mtd_info *mtd_table[MAX_MTD_DEVICES];
|
||||||
|
@ -66,7 +66,7 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||||
struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
|
struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
|
||||||
not->add(mtd);
|
not->add(mtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
up(&mtd_table_mutex);
|
up(&mtd_table_mutex);
|
||||||
/* We _know_ we aren't being removed, because
|
/* We _know_ we aren't being removed, because
|
||||||
our caller is still holding us here. So none
|
our caller is still holding us here. So none
|
||||||
|
@ -75,7 +75,7 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||||
__module_get(THIS_MODULE);
|
__module_get(THIS_MODULE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
up(&mtd_table_mutex);
|
up(&mtd_table_mutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -93,13 +93,13 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||||
int del_mtd_device (struct mtd_info *mtd)
|
int del_mtd_device (struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
down(&mtd_table_mutex);
|
down(&mtd_table_mutex);
|
||||||
|
|
||||||
if (mtd_table[mtd->index] != mtd) {
|
if (mtd_table[mtd->index] != mtd) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
} else if (mtd->usecount) {
|
} else if (mtd->usecount) {
|
||||||
printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
|
printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
|
||||||
mtd->index, mtd->name, mtd->usecount);
|
mtd->index, mtd->name, mtd->usecount);
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
} else {
|
} else {
|
||||||
|
@ -140,7 +140,7 @@ void register_mtd_user (struct mtd_notifier *new)
|
||||||
list_add(&new->list, &mtd_notifiers);
|
list_add(&new->list, &mtd_notifiers);
|
||||||
|
|
||||||
__module_get(THIS_MODULE);
|
__module_get(THIS_MODULE);
|
||||||
|
|
||||||
for (i=0; i< MAX_MTD_DEVICES; i++)
|
for (i=0; i< MAX_MTD_DEVICES; i++)
|
||||||
if (mtd_table[i])
|
if (mtd_table[i])
|
||||||
new->add(mtd_table[i]);
|
new->add(mtd_table[i]);
|
||||||
|
@ -169,7 +169,7 @@ int unregister_mtd_user (struct mtd_notifier *old)
|
||||||
for (i=0; i< MAX_MTD_DEVICES; i++)
|
for (i=0; i< MAX_MTD_DEVICES; i++)
|
||||||
if (mtd_table[i])
|
if (mtd_table[i])
|
||||||
old->remove(mtd_table[i]);
|
old->remove(mtd_table[i]);
|
||||||
|
|
||||||
list_del(&old->list);
|
list_del(&old->list);
|
||||||
up(&mtd_table_mutex);
|
up(&mtd_table_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -187,7 +187,7 @@ int unregister_mtd_user (struct mtd_notifier *old)
|
||||||
* both, return the num'th driver only if its address matches. Return NULL
|
* both, return the num'th driver only if its address matches. Return NULL
|
||||||
* if not.
|
* if not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
|
struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
|
||||||
{
|
{
|
||||||
struct mtd_info *ret = NULL;
|
struct mtd_info *ret = NULL;
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
*
|
*
|
||||||
* This code is GPL
|
* This code is GPL
|
||||||
*
|
*
|
||||||
* $Id: mtdpart.c,v 1.54 2005/09/30 14:49:08 dedekind Exp $
|
* $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $
|
||||||
*
|
*
|
||||||
* 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
|
* 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
|
||||||
* added support for read_oob, write_oob
|
* added support for read_oob, write_oob
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
@ -41,13 +41,13 @@ struct mtd_part {
|
||||||
*/
|
*/
|
||||||
#define PART(x) ((struct mtd_part *)(x))
|
#define PART(x) ((struct mtd_part *)(x))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MTD methods which simply translate the effective address and pass through
|
* MTD methods which simply translate the effective address and pass through
|
||||||
* to the _real_ device.
|
* to the _real_ device.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf)
|
size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
@ -55,15 +55,15 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (from + len > mtd->size)
|
else if (from + len > mtd->size)
|
||||||
len = mtd->size - from;
|
len = mtd->size - from;
|
||||||
if (part->master->read_ecc == NULL)
|
if (part->master->read_ecc == NULL)
|
||||||
return part->master->read (part->master, from + part->offset,
|
return part->master->read (part->master, from + part->offset,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
else
|
else
|
||||||
return part->master->read_ecc (part->master, from + part->offset,
|
return part->master->read_ecc (part->master, from + part->offset,
|
||||||
len, retlen, buf, NULL, &mtd->oobinfo);
|
len, retlen, buf, NULL, &mtd->oobinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char **buf)
|
size_t *retlen, u_char **buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
@ -71,7 +71,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (from + len > mtd->size)
|
else if (from + len > mtd->size)
|
||||||
len = mtd->size - from;
|
len = mtd->size - from;
|
||||||
return part->master->point (part->master, from + part->offset,
|
return part->master->point (part->master, from + part->offset,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
}
|
}
|
||||||
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
|
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
|
||||||
|
@ -82,7 +82,7 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
|
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
@ -92,11 +92,11 @@ static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (from + len > mtd->size)
|
else if (from + len > mtd->size)
|
||||||
len = mtd->size - from;
|
len = mtd->size - from;
|
||||||
return part->master->read_ecc (part->master, from + part->offset,
|
return part->master->read_ecc (part->master, from + part->offset,
|
||||||
len, retlen, buf, eccbuf, oobsel);
|
len, retlen, buf, eccbuf, oobsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf)
|
size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
@ -104,15 +104,15 @@ static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (from + len > mtd->size)
|
else if (from + len > mtd->size)
|
||||||
len = mtd->size - from;
|
len = mtd->size - from;
|
||||||
return part->master->read_oob (part->master, from + part->offset,
|
return part->master->read_oob (part->master, from + part->offset,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf)
|
size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->read_user_prot_reg (part->master, from,
|
return part->master->read_user_prot_reg (part->master, from,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,11 +123,11 @@ static int part_get_user_prot_info (struct mtd_info *mtd,
|
||||||
return part->master->get_user_prot_info (part->master, buf, len);
|
return part->master->get_user_prot_info (part->master, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf)
|
size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->read_fact_prot_reg (part->master, from,
|
return part->master->read_fact_prot_reg (part->master, from,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,13 +148,13 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (to + len > mtd->size)
|
else if (to + len > mtd->size)
|
||||||
len = mtd->size - to;
|
len = mtd->size - to;
|
||||||
if (part->master->write_ecc == NULL)
|
if (part->master->write_ecc == NULL)
|
||||||
return part->master->write (part->master, to + part->offset,
|
return part->master->write (part->master, to + part->offset,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
else
|
else
|
||||||
return part->master->write_ecc (part->master, to + part->offset,
|
return part->master->write_ecc (part->master, to + part->offset,
|
||||||
len, retlen, buf, NULL, &mtd->oobinfo);
|
len, retlen, buf, NULL, &mtd->oobinfo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
|
static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
@ -170,7 +170,7 @@ static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (to + len > mtd->size)
|
else if (to + len > mtd->size)
|
||||||
len = mtd->size - to;
|
len = mtd->size - to;
|
||||||
return part->master->write_ecc (part->master, to + part->offset,
|
return part->master->write_ecc (part->master, to + part->offset,
|
||||||
len, retlen, buf, eccbuf, oobsel);
|
len, retlen, buf, eccbuf, oobsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,19 +184,19 @@ static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (to + len > mtd->size)
|
else if (to + len > mtd->size)
|
||||||
len = mtd->size - to;
|
len = mtd->size - to;
|
||||||
return part->master->write_oob (part->master, to + part->offset,
|
return part->master->write_oob (part->master, to + part->offset,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
|
static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf)
|
size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->write_user_prot_reg (part->master, from,
|
return part->master->write_user_prot_reg (part->master, from,
|
||||||
len, retlen, buf);
|
len, retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
|
static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return part->master->lock_user_prot_reg (part->master, from, len);
|
return part->master->lock_user_prot_reg (part->master, from, len);
|
||||||
|
@ -208,7 +208,7 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
if (part->master->writev_ecc == NULL)
|
if (part->master->writev_ecc == NULL)
|
||||||
return part->master->writev (part->master, vecs, count,
|
return part->master->writev (part->master, vecs, count,
|
||||||
to + part->offset, retlen);
|
to + part->offset, retlen);
|
||||||
else
|
else
|
||||||
|
@ -221,12 +221,12 @@ static int part_readv (struct mtd_info *mtd, struct kvec *vecs,
|
||||||
unsigned long count, loff_t from, size_t *retlen)
|
unsigned long count, loff_t from, size_t *retlen)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (part->master->readv_ecc == NULL)
|
if (part->master->readv_ecc == NULL)
|
||||||
return part->master->readv (part->master, vecs, count,
|
return part->master->readv (part->master, vecs, count,
|
||||||
from + part->offset, retlen);
|
from + part->offset, retlen);
|
||||||
else
|
else
|
||||||
return part->master->readv_ecc (part->master, vecs, count,
|
return part->master->readv_ecc (part->master, vecs, count,
|
||||||
from + part->offset, retlen,
|
from + part->offset, retlen,
|
||||||
NULL, &mtd->oobinfo);
|
NULL, &mtd->oobinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs,
|
||||||
if (oobsel == NULL)
|
if (oobsel == NULL)
|
||||||
oobsel = &mtd->oobinfo;
|
oobsel = &mtd->oobinfo;
|
||||||
return part->master->readv_ecc (part->master, vecs, count,
|
return part->master->readv_ecc (part->master, vecs, count,
|
||||||
from + part->offset, retlen,
|
from + part->offset, retlen,
|
||||||
eccbuf, oobsel);
|
eccbuf, oobsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
|
||||||
static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
|
static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if ((len + ofs) > mtd->size)
|
if ((len + ofs) > mtd->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return part->master->lock(part->master, ofs + part->offset, len);
|
return part->master->lock(part->master, ofs + part->offset, len);
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
|
||||||
static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
|
static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if ((len + ofs) > mtd->size)
|
if ((len + ofs) > mtd->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return part->master->unlock(part->master, ofs + part->offset, len);
|
return part->master->unlock(part->master, ofs + part->offset, len);
|
||||||
}
|
}
|
||||||
|
@ -337,8 +337,8 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
|
||||||
return part->master->block_markbad(part->master, ofs);
|
return part->master->block_markbad(part->master, ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function unregisters and destroy all slave MTD objects which are
|
* This function unregisters and destroy all slave MTD objects which are
|
||||||
* attached to the given master MTD object.
|
* attached to the given master MTD object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ int del_mtd_partitions(struct mtd_info *master)
|
||||||
* (Q: should we register the master MTD object as well?)
|
* (Q: should we register the master MTD object as well?)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int add_mtd_partitions(struct mtd_info *master,
|
int add_mtd_partitions(struct mtd_info *master,
|
||||||
const struct mtd_partition *parts,
|
const struct mtd_partition *parts,
|
||||||
int nbparts)
|
int nbparts)
|
||||||
{
|
{
|
||||||
|
@ -414,7 +414,7 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||||
slave->mtd.point = part_point;
|
slave->mtd.point = part_point;
|
||||||
slave->mtd.unpoint = part_unpoint;
|
slave->mtd.unpoint = part_unpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (master->read_ecc)
|
if (master->read_ecc)
|
||||||
slave->mtd.read_ecc = part_read_ecc;
|
slave->mtd.read_ecc = part_read_ecc;
|
||||||
if (master->write_ecc)
|
if (master->write_ecc)
|
||||||
|
@ -477,8 +477,8 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||||
if (slave->mtd.size == MTDPART_SIZ_FULL)
|
if (slave->mtd.size == MTDPART_SIZ_FULL)
|
||||||
slave->mtd.size = master->size - slave->offset;
|
slave->mtd.size = master->size - slave->offset;
|
||||||
cur_offset = slave->offset + slave->mtd.size;
|
cur_offset = slave->offset + slave->mtd.size;
|
||||||
|
|
||||||
printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
|
printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
|
||||||
slave->offset + slave->mtd.size, slave->mtd.name);
|
slave->offset + slave->mtd.size, slave->mtd.name);
|
||||||
|
|
||||||
/* let's do some sanity checks */
|
/* let's do some sanity checks */
|
||||||
|
@ -498,7 +498,7 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||||
/* Deal with variable erase size stuff */
|
/* Deal with variable erase size stuff */
|
||||||
int i;
|
int i;
|
||||||
struct mtd_erase_region_info *regions = master->eraseregions;
|
struct mtd_erase_region_info *regions = master->eraseregions;
|
||||||
|
|
||||||
/* Find the first erase regions which is part of this partition. */
|
/* Find the first erase regions which is part of this partition. */
|
||||||
for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
|
for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
|
||||||
;
|
;
|
||||||
|
@ -513,7 +513,7 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||||
slave->mtd.erasesize = master->erasesize;
|
slave->mtd.erasesize = master->erasesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
||||||
(slave->offset % slave->mtd.erasesize)) {
|
(slave->offset % slave->mtd.erasesize)) {
|
||||||
/* Doesn't start on a boundary of major erase size */
|
/* Doesn't start on a boundary of major erase size */
|
||||||
/* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
|
/* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
|
||||||
|
@ -521,14 +521,14 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||||
printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
|
printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
|
||||||
parts[i].name);
|
parts[i].name);
|
||||||
}
|
}
|
||||||
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
||||||
(slave->mtd.size % slave->mtd.erasesize)) {
|
(slave->mtd.size % slave->mtd.erasesize)) {
|
||||||
slave->mtd.flags &= ~MTD_WRITEABLE;
|
slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||||
printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
|
printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
|
||||||
parts[i].name);
|
parts[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy oobinfo from master */
|
/* copy oobinfo from master */
|
||||||
memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
|
memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
|
||||||
|
|
||||||
if(parts[i].mtdp)
|
if(parts[i].mtdp)
|
||||||
|
@ -589,12 +589,12 @@ int deregister_mtd_parser(struct mtd_part_parser *p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_mtd_partitions(struct mtd_info *master, const char **types,
|
int parse_mtd_partitions(struct mtd_info *master, const char **types,
|
||||||
struct mtd_partition **pparts, unsigned long origin)
|
struct mtd_partition **pparts, unsigned long origin)
|
||||||
{
|
{
|
||||||
struct mtd_part_parser *parser;
|
struct mtd_part_parser *parser;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
for ( ; ret <= 0 && *types; types++) {
|
for ( ; ret <= 0 && *types; types++) {
|
||||||
parser = get_partition_parser(*types);
|
parser = get_partition_parser(*types);
|
||||||
#ifdef CONFIG_KMOD
|
#ifdef CONFIG_KMOD
|
||||||
|
@ -608,7 +608,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
|
||||||
}
|
}
|
||||||
ret = (*parser->parse_fn)(master, pparts, origin);
|
ret = (*parser->parse_fn)(master, pparts, origin);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
|
printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
|
||||||
ret, parser->name, master->name);
|
ret, parser->name, master->name);
|
||||||
}
|
}
|
||||||
put_partition_parser(parser);
|
put_partition_parser(parser);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* Linux driver for NAND Flash Translation Layer */
|
/* Linux driver for NAND Flash Translation Layer */
|
||||||
/* (c) 1999 Machine Vision Holdings, Inc. */
|
/* (c) 1999 Machine Vision Holdings, Inc. */
|
||||||
/* Author: David Woodhouse <dwmw2@infradead.org> */
|
/* Author: David Woodhouse <dwmw2@infradead.org> */
|
||||||
/* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */
|
/* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The contents of this file are distributed under the GNU General
|
The contents of this file are distributed under the GNU General
|
||||||
|
@ -101,14 +101,14 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||||
|
|
||||||
if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
|
if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
|
||||||
/*
|
/*
|
||||||
Oh no we don't have
|
Oh no we don't have
|
||||||
mbd.size == heads * cylinders * sectors
|
mbd.size == heads * cylinders * sectors
|
||||||
*/
|
*/
|
||||||
printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
|
printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
|
||||||
"match size of 0x%lx.\n", nftl->mbd.size);
|
"match size of 0x%lx.\n", nftl->mbd.size);
|
||||||
printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
|
printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
|
||||||
"(== 0x%lx sects)\n",
|
"(== 0x%lx sects)\n",
|
||||||
nftl->cylinders, nftl->heads , nftl->sectors,
|
nftl->cylinders, nftl->heads , nftl->sectors,
|
||||||
(long)nftl->cylinders * (long)nftl->heads *
|
(long)nftl->cylinders * (long)nftl->heads *
|
||||||
(long)nftl->sectors );
|
(long)nftl->sectors );
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
|
||||||
|
|
||||||
if (!silly--) {
|
if (!silly--) {
|
||||||
printk("Argh! No free blocks found! LastFreeEUN = %d, "
|
printk("Argh! No free blocks found! LastFreeEUN = %d, "
|
||||||
"FirstEUN = %d\n", nftl->LastFreeEUN,
|
"FirstEUN = %d\n", nftl->LastFreeEUN,
|
||||||
le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
|
le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
|
||||||
return 0xffff;
|
return 0xffff;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
"Virtual Unit Chain %d!\n", thisVUC);
|
"Virtual Unit Chain %d!\n", thisVUC);
|
||||||
return BLOCK_NIL;
|
return BLOCK_NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan to find the Erase Unit which holds the actual data for each
|
/* Scan to find the Erase Unit which holds the actual data for each
|
||||||
512-byte block within the Chain.
|
512-byte block within the Chain.
|
||||||
*/
|
*/
|
||||||
|
@ -227,7 +227,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
if (block == 2) {
|
if (block == 2) {
|
||||||
foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
|
foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
|
||||||
if (foldmark == FOLD_MARK_IN_PROGRESS) {
|
if (foldmark == FOLD_MARK_IN_PROGRESS) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL1,
|
DEBUG(MTD_DEBUG_LEVEL1,
|
||||||
"Write Inhibited on EUN %d\n", thisEUN);
|
"Write Inhibited on EUN %d\n", thisEUN);
|
||||||
inplace = 0;
|
inplace = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -249,7 +249,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
if (!BlockFreeFound[block])
|
if (!BlockFreeFound[block])
|
||||||
BlockMap[block] = thisEUN;
|
BlockMap[block] = thisEUN;
|
||||||
else
|
else
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"SECTOR_USED found after SECTOR_FREE "
|
"SECTOR_USED found after SECTOR_FREE "
|
||||||
"in Virtual Unit Chain %d for block %d\n",
|
"in Virtual Unit Chain %d for block %d\n",
|
||||||
thisVUC, block);
|
thisVUC, block);
|
||||||
|
@ -258,7 +258,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
if (!BlockFreeFound[block])
|
if (!BlockFreeFound[block])
|
||||||
BlockMap[block] = BLOCK_NIL;
|
BlockMap[block] = BLOCK_NIL;
|
||||||
else
|
else
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"SECTOR_DELETED found after SECTOR_FREE "
|
"SECTOR_DELETED found after SECTOR_FREE "
|
||||||
"in Virtual Unit Chain %d for block %d\n",
|
"in Virtual Unit Chain %d for block %d\n",
|
||||||
thisVUC, block);
|
thisVUC, block);
|
||||||
|
@ -277,14 +277,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
thisVUC);
|
thisVUC);
|
||||||
return BLOCK_NIL;
|
return BLOCK_NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
thisEUN = nftl->ReplUnitTable[thisEUN];
|
thisEUN = nftl->ReplUnitTable[thisEUN];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inplace) {
|
if (inplace) {
|
||||||
/* We're being asked to be a fold-in-place. Check
|
/* We're being asked to be a fold-in-place. Check
|
||||||
that all blocks which actually have data associated
|
that all blocks which actually have data associated
|
||||||
with them (i.e. BlockMap[block] != BLOCK_NIL) are
|
with them (i.e. BlockMap[block] != BLOCK_NIL) are
|
||||||
either already present or SECTOR_FREE in the target
|
either already present or SECTOR_FREE in the target
|
||||||
block. If not, we're going to have to fold out-of-place
|
block. If not, we're going to have to fold out-of-place
|
||||||
anyway.
|
anyway.
|
||||||
|
@ -297,7 +297,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
"block %d was %x lastEUN, "
|
"block %d was %x lastEUN, "
|
||||||
"and is in EUN %d (%s) %d\n",
|
"and is in EUN %d (%s) %d\n",
|
||||||
thisVUC, block, BlockLastState[block],
|
thisVUC, block, BlockLastState[block],
|
||||||
BlockMap[block],
|
BlockMap[block],
|
||||||
BlockMap[block]== targetEUN ? "==" : "!=",
|
BlockMap[block]== targetEUN ? "==" : "!=",
|
||||||
targetEUN);
|
targetEUN);
|
||||||
inplace = 0;
|
inplace = 0;
|
||||||
|
@ -314,17 +314,17 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
inplace = 0;
|
inplace = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inplace) {
|
if (!inplace) {
|
||||||
DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
|
DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
|
||||||
"Trying out-of-place\n", thisVUC);
|
"Trying out-of-place\n", thisVUC);
|
||||||
/* We need to find a targetEUN to fold into. */
|
/* We need to find a targetEUN to fold into. */
|
||||||
targetEUN = NFTL_findfreeblock(nftl, 1);
|
targetEUN = NFTL_findfreeblock(nftl, 1);
|
||||||
if (targetEUN == BLOCK_NIL) {
|
if (targetEUN == BLOCK_NIL) {
|
||||||
/* Ouch. Now we're screwed. We need to do a
|
/* Ouch. Now we're screwed. We need to do a
|
||||||
fold-in-place of another chain to make room
|
fold-in-place of another chain to make room
|
||||||
for this one. We need a better way of selecting
|
for this one. We need a better way of selecting
|
||||||
which chain to fold, because makefreeblock will
|
which chain to fold, because makefreeblock will
|
||||||
only ask us to fold the same one again.
|
only ask us to fold the same one again.
|
||||||
*/
|
*/
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
|
@ -338,7 +338,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
chain by selecting the longer one */
|
chain by selecting the longer one */
|
||||||
oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
|
oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
|
||||||
oob.u.c.unused = 0xffffffff;
|
oob.u.c.unused = 0xffffffff;
|
||||||
MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
|
MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
|
||||||
8, &retlen, (char *)&oob.u);
|
8, &retlen, (char *)&oob.u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,14 +361,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
happen in case of media errors or deleted blocks) */
|
happen in case of media errors or deleted blocks) */
|
||||||
if (BlockMap[block] == BLOCK_NIL)
|
if (BlockMap[block] == BLOCK_NIL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
|
ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
|
||||||
512, &retlen, movebuf);
|
512, &retlen, movebuf);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
|
ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
|
||||||
+ (block * 512), 512, &retlen,
|
+ (block * 512), 512, &retlen,
|
||||||
movebuf);
|
movebuf);
|
||||||
if (ret != -EIO)
|
if (ret != -EIO)
|
||||||
printk("Error went away on retry.\n");
|
printk("Error went away on retry.\n");
|
||||||
}
|
}
|
||||||
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
||||||
|
@ -376,18 +376,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
|
MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
|
||||||
512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
|
512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add the header so that it is now a valid chain */
|
/* add the header so that it is now a valid chain */
|
||||||
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
|
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
|
||||||
= cpu_to_le16(thisVUC);
|
= cpu_to_le16(thisVUC);
|
||||||
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
|
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
|
||||||
|
|
||||||
MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
|
MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
|
||||||
8, &retlen, (char *)&oob.u);
|
8, &retlen, (char *)&oob.u);
|
||||||
|
|
||||||
/* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
|
/* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
|
||||||
|
|
||||||
/* At this point, we have two different chains for this Virtual Unit, and no way to tell
|
/* At this point, we have two different chains for this Virtual Unit, and no way to tell
|
||||||
them apart. If we crash now, we get confused. However, both contain the same data, so we
|
them apart. If we crash now, we get confused. However, both contain the same data, so we
|
||||||
shouldn't actually lose data in this case. It's just that when we load up on a medium which
|
shouldn't actually lose data in this case. It's just that when we load up on a medium which
|
||||||
has duplicate chains, we need to free one of the chains because it's not necessary any more.
|
has duplicate chains, we need to free one of the chains because it's not necessary any more.
|
||||||
|
@ -395,7 +395,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
thisEUN = nftl->EUNtable[thisVUC];
|
thisEUN = nftl->EUNtable[thisVUC];
|
||||||
DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
|
DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
|
||||||
|
|
||||||
/* For each block in the old chain (except the targetEUN of course),
|
/* For each block in the old chain (except the targetEUN of course),
|
||||||
free it and make it available for future use */
|
free it and make it available for future use */
|
||||||
while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
|
while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
|
||||||
unsigned int EUNtmp;
|
unsigned int EUNtmp;
|
||||||
|
@ -413,7 +413,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
}
|
}
|
||||||
thisEUN = EUNtmp;
|
thisEUN = EUNtmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make this the new start of chain for thisVUC */
|
/* Make this the new start of chain for thisVUC */
|
||||||
nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
|
nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
|
||||||
nftl->EUNtable[thisVUC] = targetEUN;
|
nftl->EUNtable[thisVUC] = targetEUN;
|
||||||
|
@ -423,7 +423,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
||||||
|
|
||||||
static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
|
static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
|
||||||
{
|
{
|
||||||
/* This is the part that needs some cleverness applied.
|
/* This is the part that needs some cleverness applied.
|
||||||
For now, I'm doing the minimum applicable to actually
|
For now, I'm doing the minimum applicable to actually
|
||||||
get the thing to work.
|
get the thing to work.
|
||||||
Wear-levelling and other clever stuff needs to be implemented
|
Wear-levelling and other clever stuff needs to be implemented
|
||||||
|
@ -470,7 +470,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
|
||||||
return NFTL_foldchain (nftl, LongestChain, pendingblock);
|
return NFTL_foldchain (nftl, LongestChain, pendingblock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NFTL_findwriteunit: Return the unit number into which we can write
|
/* NFTL_findwriteunit: Return the unit number into which we can write
|
||||||
for this block. Make it available if it isn't already
|
for this block. Make it available if it isn't already
|
||||||
*/
|
*/
|
||||||
static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
||||||
|
@ -488,7 +488,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
||||||
a free space for the block in question.
|
a free space for the block in question.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This condition catches the 0x[7f]fff cases, as well as
|
/* This condition catches the 0x[7f]fff cases, as well as
|
||||||
being a sanity check for past-end-of-media access
|
being a sanity check for past-end-of-media access
|
||||||
*/
|
*/
|
||||||
lastEUN = BLOCK_NIL;
|
lastEUN = BLOCK_NIL;
|
||||||
|
@ -503,7 +503,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
||||||
|
|
||||||
MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
|
MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
|
||||||
8, &retlen, (char *)&bci);
|
8, &retlen, (char *)&bci);
|
||||||
|
|
||||||
DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
|
DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
|
||||||
block , writeEUN, le16_to_cpu(bci.Status));
|
block , writeEUN, le16_to_cpu(bci.Status));
|
||||||
|
|
||||||
|
@ -518,10 +518,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Invalid block. Don't use it any more. Must implement.
|
// Invalid block. Don't use it any more. Must implement.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!silly--) {
|
if (!silly--) {
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"Infinite loop in Virtual Unit Chain 0x%x\n",
|
"Infinite loop in Virtual Unit Chain 0x%x\n",
|
||||||
thisVUC);
|
thisVUC);
|
||||||
|
@ -532,7 +532,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
||||||
writeEUN = nftl->ReplUnitTable[writeEUN];
|
writeEUN = nftl->ReplUnitTable[writeEUN];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. We didn't find one in the existing chain, or there
|
/* OK. We didn't find one in the existing chain, or there
|
||||||
is no existing chain. */
|
is no existing chain. */
|
||||||
|
|
||||||
/* Try to find an already-free block */
|
/* Try to find an already-free block */
|
||||||
|
@ -546,12 +546,12 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
||||||
|
|
||||||
/* First remember the start of this chain */
|
/* First remember the start of this chain */
|
||||||
//u16 startEUN = nftl->EUNtable[thisVUC];
|
//u16 startEUN = nftl->EUNtable[thisVUC];
|
||||||
|
|
||||||
//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
|
//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
|
||||||
writeEUN = NFTL_makefreeblock(nftl, 0xffff);
|
writeEUN = NFTL_makefreeblock(nftl, 0xffff);
|
||||||
|
|
||||||
if (writeEUN == BLOCK_NIL) {
|
if (writeEUN == BLOCK_NIL) {
|
||||||
/* OK, we accept that the above comment is
|
/* OK, we accept that the above comment is
|
||||||
lying - there may have been free blocks
|
lying - there may have been free blocks
|
||||||
last time we called NFTL_findfreeblock(),
|
last time we called NFTL_findfreeblock(),
|
||||||
but they are reserved for when we're
|
but they are reserved for when we're
|
||||||
|
@ -562,21 +562,21 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
||||||
}
|
}
|
||||||
if (writeEUN == BLOCK_NIL) {
|
if (writeEUN == BLOCK_NIL) {
|
||||||
/* Ouch. This should never happen - we should
|
/* Ouch. This should never happen - we should
|
||||||
always be able to make some room somehow.
|
always be able to make some room somehow.
|
||||||
If we get here, we've allocated more storage
|
If we get here, we've allocated more storage
|
||||||
space than actual media, or our makefreeblock
|
space than actual media, or our makefreeblock
|
||||||
routine is missing something.
|
routine is missing something.
|
||||||
*/
|
*/
|
||||||
printk(KERN_WARNING "Cannot make free space.\n");
|
printk(KERN_WARNING "Cannot make free space.\n");
|
||||||
return BLOCK_NIL;
|
return BLOCK_NIL;
|
||||||
}
|
}
|
||||||
//printk("Restarting scan\n");
|
//printk("Restarting scan\n");
|
||||||
lastEUN = BLOCK_NIL;
|
lastEUN = BLOCK_NIL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We've found a free block. Insert it into the chain. */
|
/* We've found a free block. Insert it into the chain. */
|
||||||
|
|
||||||
if (lastEUN != BLOCK_NIL) {
|
if (lastEUN != BLOCK_NIL) {
|
||||||
thisVUC |= 0x8000; /* It's a replacement block */
|
thisVUC |= 0x8000; /* It's a replacement block */
|
||||||
} else {
|
} else {
|
||||||
|
@ -749,7 +749,7 @@ extern char nftlmountrev[];
|
||||||
|
|
||||||
static int __init init_nftl(void)
|
static int __init init_nftl(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev);
|
printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev);
|
||||||
|
|
||||||
return register_mtd_blktrans(&nftl_tr);
|
return register_mtd_blktrans(&nftl_tr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* NFTL mount code with extensive checks
|
* NFTL mount code with extensive checks
|
||||||
*
|
*
|
||||||
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
|
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
|
||||||
* Copyright (C) 2000 Netgem S.A.
|
* Copyright (C) 2000 Netgem S.A.
|
||||||
*
|
*
|
||||||
* $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $
|
* $Id: nftlmount.c,v 1.41 2005/11/07 11:14:21 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
#define SECTORSIZE 512
|
#define SECTORSIZE 512
|
||||||
|
|
||||||
char nftlmountrev[]="$Revision: 1.40 $";
|
char nftlmountrev[]="$Revision: 1.41 $";
|
||||||
|
|
||||||
/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
|
/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
|
||||||
* various device information of the NFTL partition and Bad Unit Table. Update
|
* various device information of the NFTL partition and Bad Unit Table. Update
|
||||||
|
@ -47,7 +47,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
|
||||||
struct NFTLMediaHeader *mh = &nftl->MediaHdr;
|
struct NFTLMediaHeader *mh = &nftl->MediaHdr;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* Assume logical EraseSize == physical erasesize for starting the scan.
|
/* Assume logical EraseSize == physical erasesize for starting the scan.
|
||||||
We'll sort it out later if we find a MediaHeader which says otherwise */
|
We'll sort it out later if we find a MediaHeader which says otherwise */
|
||||||
/* Actually, we won't. The new DiskOnChip driver has already scanned
|
/* Actually, we won't. The new DiskOnChip driver has already scanned
|
||||||
the MediaHeader and adjusted the virtual erasesize it presents in
|
the MediaHeader and adjusted the virtual erasesize it presents in
|
||||||
|
@ -83,9 +83,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
|
||||||
if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
|
if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
|
||||||
/* ANAND\0 not found. Continue */
|
/* ANAND\0 not found. Continue */
|
||||||
#if 0
|
#if 0
|
||||||
printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
|
printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
|
||||||
block * nftl->EraseSize, nftl->mbd.mtd->index);
|
block * nftl->EraseSize, nftl->mbd.mtd->index);
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
|
||||||
*/
|
*/
|
||||||
if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
|
if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
|
||||||
printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
|
printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
|
||||||
block * nftl->EraseSize, nftl->mbd.mtd->index,
|
block * nftl->EraseSize, nftl->mbd.mtd->index,
|
||||||
le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
|
le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ device is already correct.
|
||||||
nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
|
nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
|
||||||
if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
|
if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
|
||||||
printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
|
printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
|
||||||
printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
|
printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
|
||||||
nftl->nb_boot_blocks, nftl->nb_blocks);
|
nftl->nb_boot_blocks, nftl->nb_blocks);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ device is already correct.
|
||||||
nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
|
nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
|
nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
|
||||||
|
|
||||||
/* If we're not using the last sectors in the device for some reason,
|
/* If we're not using the last sectors in the device for some reason,
|
||||||
|
@ -210,12 +210,12 @@ device is already correct.
|
||||||
printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
|
printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
|
/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
|
||||||
for (i = 0; i < nftl->nb_boot_blocks; i++)
|
for (i = 0; i < nftl->nb_boot_blocks; i++)
|
||||||
nftl->ReplUnitTable[i] = BLOCK_RESERVED;
|
nftl->ReplUnitTable[i] = BLOCK_RESERVED;
|
||||||
/* mark all remaining blocks as potentially containing data */
|
/* mark all remaining blocks as potentially containing data */
|
||||||
for (; i < nftl->nb_blocks; i++) {
|
for (; i < nftl->nb_blocks; i++) {
|
||||||
nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
|
nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,12 +245,12 @@ The new DiskOnChip driver already scanned the bad block table. Just query it.
|
||||||
if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize))
|
if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize))
|
||||||
nftl->ReplUnitTable[i] = BLOCK_RESERVED;
|
nftl->ReplUnitTable[i] = BLOCK_RESERVED;
|
||||||
}
|
}
|
||||||
|
|
||||||
nftl->MediaUnit = block;
|
nftl->MediaUnit = block;
|
||||||
boot_record_count++;
|
boot_record_count++;
|
||||||
|
|
||||||
} /* foreach (block) */
|
} /* foreach (block) */
|
||||||
|
|
||||||
return boot_record_count?0:-1;
|
return boot_record_count?0:-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ static int memcmpb(void *a, int c, int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */
|
/* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */
|
||||||
static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
|
static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
|
||||||
int check_oob)
|
int check_oob)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -293,7 +293,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
|
||||||
*
|
*
|
||||||
* Return: 0 when succeed, -1 on error.
|
* Return: 0 when succeed, -1 on error.
|
||||||
*
|
*
|
||||||
* ToDo: 1. Is it neceressary to check_free_sector after erasing ??
|
* ToDo: 1. Is it neceressary to check_free_sector after erasing ??
|
||||||
*/
|
*/
|
||||||
int NFTL_formatblock(struct NFTLrecord *nftl, int block)
|
int NFTL_formatblock(struct NFTLrecord *nftl, int block)
|
||||||
{
|
{
|
||||||
|
@ -385,7 +385,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
|
||||||
/* verify that the sector is really free. If not, mark
|
/* verify that the sector is really free. If not, mark
|
||||||
as ignore */
|
as ignore */
|
||||||
if (memcmpb(&bci, 0xff, 8) != 0 ||
|
if (memcmpb(&bci, 0xff, 8) != 0 ||
|
||||||
check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE,
|
check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE,
|
||||||
SECTORSIZE, 0) != 0) {
|
SECTORSIZE, 0) != 0) {
|
||||||
printk("Incorrect free sector %d in block %d: "
|
printk("Incorrect free sector %d in block %d: "
|
||||||
"marking it as ignored\n",
|
"marking it as ignored\n",
|
||||||
|
@ -486,7 +486,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
|
|
||||||
/* check erase mark. */
|
/* check erase mark. */
|
||||||
if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
|
if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
|
||||||
&retlen, (char *)&h1) < 0)
|
&retlen, (char *)&h1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -501,7 +501,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
|
||||||
h1.EraseMark = cpu_to_le16(ERASE_MARK);
|
h1.EraseMark = cpu_to_le16(ERASE_MARK);
|
||||||
h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
|
h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
|
||||||
h1.WearInfo = cpu_to_le32(0);
|
h1.WearInfo = cpu_to_le32(0);
|
||||||
if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
|
if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
|
||||||
&retlen, (char *)&h1) < 0)
|
&retlen, (char *)&h1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -582,9 +582,9 @@ int NFTL_mount(struct NFTLrecord *s)
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* read the block header. If error, we format the chain */
|
/* read the block header. If error, we format the chain */
|
||||||
if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8,
|
if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8,
|
||||||
&retlen, (char *)&h0) < 0 ||
|
&retlen, (char *)&h0) < 0 ||
|
||||||
MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
|
MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
|
||||||
&retlen, (char *)&h1) < 0) {
|
&retlen, (char *)&h1) < 0) {
|
||||||
s->ReplUnitTable[block] = BLOCK_NIL;
|
s->ReplUnitTable[block] = BLOCK_NIL;
|
||||||
do_format_chain = 1;
|
do_format_chain = 1;
|
||||||
|
@ -639,7 +639,7 @@ int NFTL_mount(struct NFTLrecord *s)
|
||||||
first_logical_block = logical_block;
|
first_logical_block = logical_block;
|
||||||
} else {
|
} else {
|
||||||
if (logical_block != first_logical_block) {
|
if (logical_block != first_logical_block) {
|
||||||
printk("Block %d: incorrect logical block: %d expected: %d\n",
|
printk("Block %d: incorrect logical block: %d expected: %d\n",
|
||||||
block, logical_block, first_logical_block);
|
block, logical_block, first_logical_block);
|
||||||
/* the chain is incorrect : we must format it,
|
/* the chain is incorrect : we must format it,
|
||||||
but we need to read it completly */
|
but we need to read it completly */
|
||||||
|
@ -668,7 +668,7 @@ int NFTL_mount(struct NFTLrecord *s)
|
||||||
s->ReplUnitTable[block] = BLOCK_NIL;
|
s->ReplUnitTable[block] = BLOCK_NIL;
|
||||||
break;
|
break;
|
||||||
} else if (rep_block >= s->nb_blocks) {
|
} else if (rep_block >= s->nb_blocks) {
|
||||||
printk("Block %d: referencing invalid block %d\n",
|
printk("Block %d: referencing invalid block %d\n",
|
||||||
block, rep_block);
|
block, rep_block);
|
||||||
do_format_chain = 1;
|
do_format_chain = 1;
|
||||||
s->ReplUnitTable[block] = BLOCK_NIL;
|
s->ReplUnitTable[block] = BLOCK_NIL;
|
||||||
|
@ -688,7 +688,7 @@ int NFTL_mount(struct NFTLrecord *s)
|
||||||
s->ReplUnitTable[block] = rep_block;
|
s->ReplUnitTable[block] = rep_block;
|
||||||
s->EUNtable[first_logical_block] = BLOCK_NIL;
|
s->EUNtable[first_logical_block] = BLOCK_NIL;
|
||||||
} else {
|
} else {
|
||||||
printk("Block %d: referencing block %d already in another chain\n",
|
printk("Block %d: referencing block %d already in another chain\n",
|
||||||
block, rep_block);
|
block, rep_block);
|
||||||
/* XXX: should handle correctly fold in progress chains */
|
/* XXX: should handle correctly fold in progress chains */
|
||||||
do_format_chain = 1;
|
do_format_chain = 1;
|
||||||
|
@ -710,7 +710,7 @@ int NFTL_mount(struct NFTLrecord *s)
|
||||||
} else {
|
} else {
|
||||||
unsigned int first_block1, chain_to_format, chain_length1;
|
unsigned int first_block1, chain_to_format, chain_length1;
|
||||||
int fold_mark;
|
int fold_mark;
|
||||||
|
|
||||||
/* valid chain : get foldmark */
|
/* valid chain : get foldmark */
|
||||||
fold_mark = get_fold_mark(s, first_block);
|
fold_mark = get_fold_mark(s, first_block);
|
||||||
if (fold_mark == 0) {
|
if (fold_mark == 0) {
|
||||||
|
@ -729,9 +729,9 @@ int NFTL_mount(struct NFTLrecord *s)
|
||||||
if (first_block1 != BLOCK_NIL) {
|
if (first_block1 != BLOCK_NIL) {
|
||||||
/* XXX: what to do if same length ? */
|
/* XXX: what to do if same length ? */
|
||||||
chain_length1 = calc_chain_length(s, first_block1);
|
chain_length1 = calc_chain_length(s, first_block1);
|
||||||
printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n",
|
printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n",
|
||||||
first_block1, chain_length1, first_block, chain_length);
|
first_block1, chain_length1, first_block, chain_length);
|
||||||
|
|
||||||
if (chain_length >= chain_length1) {
|
if (chain_length >= chain_length1) {
|
||||||
chain_to_format = first_block1;
|
chain_to_format = first_block1;
|
||||||
s->EUNtable[first_logical_block] = first_block;
|
s->EUNtable[first_logical_block] = first_block;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $
|
* $Id: redboot.c,v 1.18 2005/11/07 11:14:21 gleixner Exp $
|
||||||
*
|
*
|
||||||
* Parse RedBoot-style Flash Image System (FIS) tables and
|
* Parse RedBoot-style Flash Image System (FIS) tables and
|
||||||
* produce a Linux partition array to match.
|
* produce a Linux partition array to match.
|
||||||
|
@ -39,7 +39,7 @@ static inline int redboot_checksum(struct fis_image_desc *img)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_redboot_partitions(struct mtd_info *master,
|
static int parse_redboot_partitions(struct mtd_info *master,
|
||||||
struct mtd_partition **pparts,
|
struct mtd_partition **pparts,
|
||||||
unsigned long fis_origin)
|
unsigned long fis_origin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Sean Young <sean@mess.org>
|
* Copyright (C) 2005 Sean Young <sean@mess.org>
|
||||||
*
|
*
|
||||||
* $Id: rfd_ftl.c,v 1.4 2005/07/31 22:49:14 sean Exp $
|
* $Id: rfd_ftl.c,v 1.5 2005/11/07 11:14:21 gleixner Exp $
|
||||||
*
|
*
|
||||||
* This type of flash translation layer (FTL) is used by the Embedded BIOS
|
* This type of flash translation layer (FTL) is used by the Embedded BIOS
|
||||||
* by General Software. It is known as the Resident Flash Disk (RFD), see:
|
* by General Software. It is known as the Resident Flash Disk (RFD), see:
|
||||||
|
@ -95,7 +95,7 @@ static int build_block_map(struct partition *part, int block_no)
|
||||||
{
|
{
|
||||||
struct block *block = &part->blocks[block_no];
|
struct block *block = &part->blocks[block_no];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
block->offset = part->block_size * block_no;
|
block->offset = part->block_size * block_no;
|
||||||
|
|
||||||
if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) {
|
if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) {
|
||||||
|
@ -109,12 +109,12 @@ static int build_block_map(struct partition *part, int block_no)
|
||||||
|
|
||||||
for (i=0; i<part->data_sectors_per_block; i++) {
|
for (i=0; i<part->data_sectors_per_block; i++) {
|
||||||
u16 entry;
|
u16 entry;
|
||||||
|
|
||||||
entry = le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]);
|
entry = le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]);
|
||||||
|
|
||||||
if (entry == SECTOR_DELETED)
|
if (entry == SECTOR_DELETED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (entry == SECTOR_FREE) {
|
if (entry == SECTOR_FREE) {
|
||||||
block->free_sectors++;
|
block->free_sectors++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -122,9 +122,9 @@ static int build_block_map(struct partition *part, int block_no)
|
||||||
|
|
||||||
if (entry == SECTOR_ZERO)
|
if (entry == SECTOR_ZERO)
|
||||||
entry = 0;
|
entry = 0;
|
||||||
|
|
||||||
if (entry >= part->sector_count) {
|
if (entry >= part->sector_count) {
|
||||||
printk(KERN_NOTICE PREFIX
|
printk(KERN_NOTICE PREFIX
|
||||||
"'%s': unit #%d: entry %d corrupt, "
|
"'%s': unit #%d: entry %d corrupt, "
|
||||||
"sector %d out of range\n",
|
"sector %d out of range\n",
|
||||||
part->mbd.mtd->name, block_no, i, entry);
|
part->mbd.mtd->name, block_no, i, entry);
|
||||||
|
@ -132,14 +132,14 @@ static int build_block_map(struct partition *part, int block_no)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part->sector_map[entry] != -1) {
|
if (part->sector_map[entry] != -1) {
|
||||||
printk(KERN_NOTICE PREFIX
|
printk(KERN_NOTICE PREFIX
|
||||||
"'%s': more than one entry for sector %d\n",
|
"'%s': more than one entry for sector %d\n",
|
||||||
part->mbd.mtd->name, entry);
|
part->mbd.mtd->name, entry);
|
||||||
part->errors = 1;
|
part->errors = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
part->sector_map[entry] = block->offset +
|
part->sector_map[entry] = block->offset +
|
||||||
(i + part->header_sectors_per_block) * SECTOR_SIZE;
|
(i + part->header_sectors_per_block) * SECTOR_SIZE;
|
||||||
|
|
||||||
block->used_sectors++;
|
block->used_sectors++;
|
||||||
|
@ -165,14 +165,14 @@ static int scan_header(struct partition *part)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
/* each erase block has three bytes header, followed by the map */
|
/* each erase block has three bytes header, followed by the map */
|
||||||
part->header_sectors_per_block =
|
part->header_sectors_per_block =
|
||||||
((HEADER_MAP_OFFSET + sectors_per_block) *
|
((HEADER_MAP_OFFSET + sectors_per_block) *
|
||||||
sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
||||||
|
|
||||||
part->data_sectors_per_block = sectors_per_block -
|
part->data_sectors_per_block = sectors_per_block -
|
||||||
part->header_sectors_per_block;
|
part->header_sectors_per_block;
|
||||||
|
|
||||||
part->header_size = (HEADER_MAP_OFFSET +
|
part->header_size = (HEADER_MAP_OFFSET +
|
||||||
part->data_sectors_per_block) * sizeof(u16);
|
part->data_sectors_per_block) * sizeof(u16);
|
||||||
|
|
||||||
part->cylinders = (part->data_sectors_per_block *
|
part->cylinders = (part->data_sectors_per_block *
|
||||||
|
@ -188,7 +188,7 @@ static int scan_header(struct partition *part)
|
||||||
if (!part->header_cache)
|
if (!part->header_cache)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
part->blocks = kcalloc(part->total_blocks, sizeof(struct block),
|
part->blocks = kcalloc(part->total_blocks, sizeof(struct block),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!part->blocks)
|
if (!part->blocks)
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -200,18 +200,18 @@ static int scan_header(struct partition *part)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<part->sector_count; i++)
|
for (i=0; i<part->sector_count; i++)
|
||||||
part->sector_map[i] = -1;
|
part->sector_map[i] = -1;
|
||||||
|
|
||||||
for (i=0, blocks_found=0; i<part->total_blocks; i++) {
|
for (i=0, blocks_found=0; i<part->total_blocks; i++) {
|
||||||
rc = part->mbd.mtd->read(part->mbd.mtd,
|
rc = part->mbd.mtd->read(part->mbd.mtd,
|
||||||
i * part->block_size, part->header_size,
|
i * part->block_size, part->header_size,
|
||||||
&retlen, (u_char*)part->header_cache);
|
&retlen, (u_char*)part->header_cache);
|
||||||
|
|
||||||
if (!rc && retlen != part->header_size)
|
if (!rc && retlen != part->header_size)
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (!build_block_map(part, i))
|
if (!build_block_map(part, i))
|
||||||
|
@ -226,7 +226,7 @@ static int scan_header(struct partition *part)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part->reserved_block == -1) {
|
if (part->reserved_block == -1) {
|
||||||
printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n",
|
printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n",
|
||||||
part->mbd.mtd->name);
|
part->mbd.mtd->name);
|
||||||
|
|
||||||
part->errors = 1;
|
part->errors = 1;
|
||||||
|
@ -248,7 +248,7 @@ static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *b
|
||||||
u_long addr;
|
u_long addr;
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (sector >= part->sector_count)
|
if (sector >= part->sector_count)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
@ -266,9 +266,9 @@ static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *b
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
memset(buf, 0, SECTOR_SIZE);
|
memset(buf, 0, SECTOR_SIZE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void erase_callback(struct erase_info *erase)
|
static void erase_callback(struct erase_info *erase)
|
||||||
{
|
{
|
||||||
|
@ -288,7 +288,7 @@ static void erase_callback(struct erase_info *erase)
|
||||||
|
|
||||||
if (erase->state != MTD_ERASE_DONE) {
|
if (erase->state != MTD_ERASE_DONE) {
|
||||||
printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', "
|
printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', "
|
||||||
"state %d\n", erase->addr,
|
"state %d\n", erase->addr,
|
||||||
part->mbd.mtd->name, erase->state);
|
part->mbd.mtd->name, erase->state);
|
||||||
|
|
||||||
part->blocks[i].state = BLOCK_FAILED;
|
part->blocks[i].state = BLOCK_FAILED;
|
||||||
|
@ -307,17 +307,17 @@ static void erase_callback(struct erase_info *erase)
|
||||||
part->blocks[i].used_sectors = 0;
|
part->blocks[i].used_sectors = 0;
|
||||||
part->blocks[i].erases++;
|
part->blocks[i].erases++;
|
||||||
|
|
||||||
rc = part->mbd.mtd->write(part->mbd.mtd,
|
rc = part->mbd.mtd->write(part->mbd.mtd,
|
||||||
part->blocks[i].offset, sizeof(magic), &retlen,
|
part->blocks[i].offset, sizeof(magic), &retlen,
|
||||||
(u_char*)&magic);
|
(u_char*)&magic);
|
||||||
|
|
||||||
if (!rc && retlen != sizeof(magic))
|
if (!rc && retlen != sizeof(magic))
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_NOTICE PREFIX "'%s': unable to write RFD "
|
printk(KERN_NOTICE PREFIX "'%s': unable to write RFD "
|
||||||
"header at 0x%lx\n",
|
"header at 0x%lx\n",
|
||||||
part->mbd.mtd->name,
|
part->mbd.mtd->name,
|
||||||
part->blocks[i].offset);
|
part->blocks[i].offset);
|
||||||
part->blocks[i].state = BLOCK_FAILED;
|
part->blocks[i].state = BLOCK_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -374,17 +374,17 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old
|
||||||
map = kmalloc(part->header_size, GFP_KERNEL);
|
map = kmalloc(part->header_size, GFP_KERNEL);
|
||||||
if (!map)
|
if (!map)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
rc = part->mbd.mtd->read(part->mbd.mtd,
|
rc = part->mbd.mtd->read(part->mbd.mtd,
|
||||||
part->blocks[block_no].offset, part->header_size,
|
part->blocks[block_no].offset, part->header_size,
|
||||||
&retlen, (u_char*)map);
|
&retlen, (u_char*)map);
|
||||||
|
|
||||||
if (!rc && retlen != part->header_size)
|
if (!rc && retlen != part->header_size)
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_NOTICE PREFIX "error reading '%s' at "
|
printk(KERN_NOTICE PREFIX "error reading '%s' at "
|
||||||
"0x%lx\n", part->mbd.mtd->name,
|
"0x%lx\n", part->mbd.mtd->name,
|
||||||
part->blocks[block_no].offset);
|
part->blocks[block_no].offset);
|
||||||
|
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -398,11 +398,11 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old
|
||||||
if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
|
if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (entry == SECTOR_ZERO)
|
if (entry == SECTOR_ZERO)
|
||||||
entry = 0;
|
entry = 0;
|
||||||
|
|
||||||
/* already warned about and ignored in build_block_map() */
|
/* already warned about and ignored in build_block_map() */
|
||||||
if (entry >= part->sector_count)
|
if (entry >= part->sector_count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
addr = part->blocks[block_no].offset +
|
addr = part->blocks[block_no].offset +
|
||||||
|
@ -418,7 +418,7 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old
|
||||||
}
|
}
|
||||||
rc = part->mbd.mtd->read(part->mbd.mtd, addr,
|
rc = part->mbd.mtd->read(part->mbd.mtd, addr,
|
||||||
SECTOR_SIZE, &retlen, sector_data);
|
SECTOR_SIZE, &retlen, sector_data);
|
||||||
|
|
||||||
if (!rc && retlen != SECTOR_SIZE)
|
if (!rc && retlen != SECTOR_SIZE)
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
|
||||||
|
@ -429,11 +429,11 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old
|
||||||
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part,
|
rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part,
|
||||||
entry, sector_data);
|
entry, sector_data);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,11 +447,11 @@ err3:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reclaim_block(struct partition *part, u_long *old_sector)
|
static int reclaim_block(struct partition *part, u_long *old_sector)
|
||||||
{
|
{
|
||||||
int block, best_block, score, old_sector_block;
|
int block, best_block, score, old_sector_block;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* we have a race if sync doesn't exist */
|
/* we have a race if sync doesn't exist */
|
||||||
if (part->mbd.mtd->sync)
|
if (part->mbd.mtd->sync)
|
||||||
part->mbd.mtd->sync(part->mbd.mtd);
|
part->mbd.mtd->sync(part->mbd.mtd);
|
||||||
|
@ -474,16 +474,16 @@ static int reclaim_block(struct partition *part, u_long *old_sector)
|
||||||
* more removed sectors is more efficient (have to move
|
* more removed sectors is more efficient (have to move
|
||||||
* less).
|
* less).
|
||||||
*/
|
*/
|
||||||
if (part->blocks[block].free_sectors)
|
if (part->blocks[block].free_sectors)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
this_score = part->blocks[block].used_sectors;
|
this_score = part->blocks[block].used_sectors;
|
||||||
|
|
||||||
if (block == old_sector_block)
|
if (block == old_sector_block)
|
||||||
this_score--;
|
this_score--;
|
||||||
else {
|
else {
|
||||||
/* no point in moving a full block */
|
/* no point in moving a full block */
|
||||||
if (part->blocks[block].used_sectors ==
|
if (part->blocks[block].used_sectors ==
|
||||||
part->data_sectors_per_block)
|
part->data_sectors_per_block)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ static int find_free_block(const struct partition *part)
|
||||||
stop = block;
|
stop = block;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (part->blocks[block].free_sectors &&
|
if (part->blocks[block].free_sectors &&
|
||||||
block != part->reserved_block)
|
block != part->reserved_block)
|
||||||
return block;
|
return block;
|
||||||
|
|
||||||
|
@ -563,7 +563,7 @@ static int find_writeable_block(struct partition *part, u_long *old_sector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset,
|
rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset,
|
||||||
part->header_size, &retlen, (u_char*)part->header_cache);
|
part->header_size, &retlen, (u_char*)part->header_cache);
|
||||||
|
|
||||||
if (!rc && retlen != part->header_size)
|
if (!rc && retlen != part->header_size)
|
||||||
|
@ -571,7 +571,7 @@ static int find_writeable_block(struct partition *part, u_long *old_sector)
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_NOTICE PREFIX "'%s': unable to read header at "
|
printk(KERN_NOTICE PREFIX "'%s': unable to read header at "
|
||||||
"0x%lx\n", part->mbd.mtd->name,
|
"0x%lx\n", part->mbd.mtd->name,
|
||||||
part->blocks[block].offset);
|
part->blocks[block].offset);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
@ -580,7 +580,7 @@ static int find_writeable_block(struct partition *part, u_long *old_sector)
|
||||||
|
|
||||||
err:
|
err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mark_sector_deleted(struct partition *part, u_long old_addr)
|
static int mark_sector_deleted(struct partition *part, u_long old_addr)
|
||||||
{
|
{
|
||||||
|
@ -590,7 +590,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr)
|
||||||
u16 del = const_cpu_to_le16(SECTOR_DELETED);
|
u16 del = const_cpu_to_le16(SECTOR_DELETED);
|
||||||
|
|
||||||
block = old_addr / part->block_size;
|
block = old_addr / part->block_size;
|
||||||
offset = (old_addr % part->block_size) / SECTOR_SIZE -
|
offset = (old_addr % part->block_size) / SECTOR_SIZE -
|
||||||
part->header_sectors_per_block;
|
part->header_sectors_per_block;
|
||||||
|
|
||||||
addr = part->blocks[block].offset +
|
addr = part->blocks[block].offset +
|
||||||
|
@ -604,7 +604,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr)
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_WARNING PREFIX "error writing '%s' at "
|
printk(KERN_WARNING PREFIX "error writing '%s' at "
|
||||||
"0x%lx\n", part->mbd.mtd->name, addr);
|
"0x%lx\n", part->mbd.mtd->name, addr);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (block == part->current_block)
|
if (block == part->current_block)
|
||||||
|
@ -627,7 +627,7 @@ static int find_free_sector(const struct partition *part, const struct block *bl
|
||||||
i = stop = part->data_sectors_per_block - block->free_sectors;
|
i = stop = part->data_sectors_per_block - block->free_sectors;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i])
|
if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i])
|
||||||
== SECTOR_FREE)
|
== SECTOR_FREE)
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
|
@ -653,7 +653,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
|
||||||
!part->blocks[part->current_block].free_sectors) {
|
!part->blocks[part->current_block].free_sectors) {
|
||||||
|
|
||||||
rc = find_writeable_block(part, old_addr);
|
rc = find_writeable_block(part, old_addr);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,10 +665,10 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
|
||||||
rc = -ENOSPC;
|
rc = -ENOSPC;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = (i + part->header_sectors_per_block) * SECTOR_SIZE +
|
addr = (i + part->header_sectors_per_block) * SECTOR_SIZE +
|
||||||
block->offset;
|
block->offset;
|
||||||
rc = part->mbd.mtd->write(part->mbd.mtd,
|
rc = part->mbd.mtd->write(part->mbd.mtd,
|
||||||
addr, SECTOR_SIZE, &retlen, (u_char*)buf);
|
addr, SECTOR_SIZE, &retlen, (u_char*)buf);
|
||||||
|
|
||||||
if (!rc && retlen != SECTOR_SIZE)
|
if (!rc && retlen != SECTOR_SIZE)
|
||||||
|
@ -677,7 +677,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
|
printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
|
||||||
part->mbd.mtd->name, addr);
|
part->mbd.mtd->name, addr);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,7 +697,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
|
printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
|
||||||
part->mbd.mtd->name, addr);
|
part->mbd.mtd->name, addr);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
block->used_sectors++;
|
block->used_sectors++;
|
||||||
|
@ -738,7 +738,7 @@ static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == SECTOR_SIZE)
|
if (i == SECTOR_SIZE)
|
||||||
part->sector_map[sector] = -1;
|
part->sector_map[sector] = -1;
|
||||||
|
|
||||||
if (old_addr != -1)
|
if (old_addr != -1)
|
||||||
|
@ -801,7 +801,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||||
|
|
||||||
if (!add_mtd_blktrans_dev((void*)part))
|
if (!add_mtd_blktrans_dev((void*)part))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(part);
|
kfree(part);
|
||||||
}
|
}
|
||||||
|
@ -828,7 +828,7 @@ struct mtd_blktrans_ops rfd_ftl_tr = {
|
||||||
.major = RFD_FTL_MAJOR,
|
.major = RFD_FTL_MAJOR,
|
||||||
.part_bits = PART_BITS,
|
.part_bits = PART_BITS,
|
||||||
.readsect = rfd_ftl_readsect,
|
.readsect = rfd_ftl_readsect,
|
||||||
.writesect = rfd_ftl_writesect,
|
.writesect = rfd_ftl_writesect,
|
||||||
.getgeo = rfd_ftl_getgeo,
|
.getgeo = rfd_ftl_getgeo,
|
||||||
.add_mtd = rfd_ftl_add_mtd,
|
.add_mtd = rfd_ftl_add_mtd,
|
||||||
.remove_dev = rfd_ftl_remove_dev,
|
.remove_dev = rfd_ftl_remove_dev,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче