mtd/drivers/mtd/nand nand.c,1.36,1.37
gleixner at infradead.org
gleixner at infradead.org
Fri Feb 14 17:58:01 EST 2003
Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv6713
Modified Files:
nand.c
Log Message:
deny not page aligned writes, fixed ecc_select in nand_write_page
Index: nand.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -r1.36 -r1.37
--- nand.c 5 Dec 2002 20:59:11 -0000 1.36
+++ nand.c 14 Feb 2003 22:57:58 -0000 1.37
@@ -112,8 +112,11 @@
* for mtd->read_ecc / mtd->write_ecc
* some minor cleanups
*
- * 12-05-2000 tglx: Dave Ellis (DGE at sixnetio) provided the fix for
+ * 12-05-2002 tglx: Dave Ellis (DGE at sixnetio) provided the fix for
* WRITE_VERIFY long time ago. Thanks for remembering me.
+ *
+ * 02-14-2003 tglx: Reject non page aligned writes
+ * Fixed ecc select in nand_write_page to match semantics.
*
* $Id$
*
@@ -170,8 +173,7 @@
unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, int oobsel);
static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
static void nand_sync (struct mtd_info *mtd);
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, int col,
- int last, u_char *oob_buf, int oobsel);
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, int oobsel);
/*
* Send command to NAND device
*/
@@ -352,9 +354,10 @@
/*
* Nand_page_program function is used for write and writev !
+ * This function will always program a full page of data
+ * If you call it with a non page aligned buffer, you're lost :)
*/
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this,
- int page, int col, int last, u_char *oob_buf, int oobsel)
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, int oobsel)
{
int i, status;
u_char ecc_code[6], *oob_data;
@@ -369,47 +372,24 @@
} else
oob_data = oob_buf;
- /* software ecc 3 Bytes ECC / 256 Byte Data ? */
- if (eccmode == NAND_ECC_SOFT) {
- /* Read back previous written data, if col > 0 */
- if (col) {
- this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
- for (i = 0; i < col; i++)
- this->data_poi[i] = readb (this->IO_ADDR_R);
- }
- if ((col < this->eccsize) && (last >= this->eccsize)) {
- this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
- for (i = 0; i < 3; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- }
- /* Calculate and write the second ECC if we have enough data */
- if ((mtd->oobblock == 512) && (last == 512)) {
- this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
- for (i = 3; i < 6; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- }
- } else {
- /* For hardware ECC skip ECC, if we have no full page write */
- if (eccmode != NAND_ECC_NONE && (col || last != mtd->oobblock))
- eccmode = NAND_ECC_NONE;
- }
-
- /* Prepad for partial page programming !!! */
- for (i = 0; i < col; i++)
- this->data_poi[i] = 0xff;
-
- /* Postpad for partial page programming !!! oob is already padded */
- for (i = last; i < mtd->oobblock; i++)
- this->data_poi[i] = 0xff;
-
/* Send command to begin auto page programming */
this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
/* Write out complete page of data, take care of eccmode */
- switch (this->eccmode) {
+ switch (eccmode) {
/* No ecc and software ecc 3/256, write all */
case NAND_ECC_NONE:
+ printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended");
case NAND_ECC_SOFT:
+ this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
+ for (i = 0; i < 3; i++)
+ oob_data[oob_config[i]] = ecc_code[i];
+ /* Calculate and write the second ECC for 512 Byte page size */
+ if (mtd->oobblock == 512) {
+ this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
+ for (i = 3; i < 6; i++)
+ oob_data[oob_config[i]] = ecc_code[i];
+ }
for (i = 0; i < mtd->oobblock; i++)
writeb ( this->data_poi[i] , this->IO_ADDR_W);
break;
@@ -490,9 +470,9 @@
*/
/* Send command to read back the page */
- this->cmdfunc (mtd, NAND_CMD_READ0, col, page);
+ this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
/* Loop through and verify the data */
- for (i = col; i < last; i++) {
+ for (i = 0; i < mtd->oobblock; i++) {
if (this->data_poi[i] != readb (this->IO_ADDR_R)) {
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
return -EIO;
@@ -508,7 +488,7 @@
}
}
} else {
- if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) {
+ if (eccmode != NAND_ECC_NONE) {
int ecc_bytes = 0;
switch (this->eccmode) {
@@ -780,6 +760,8 @@
return 0;
}
+#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
+
/*
* Use NAND write ECC
*/
@@ -793,23 +775,26 @@
static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel)
{
- int i, page, col, cnt, ret = 0, oob = 0, written = 0;
+ int page, ret = 0, oob = 0, written = 0;
struct nand_chip *this = mtd->priv;
DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
/* Do not allow write past end of device */
if ((to + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
+ return -EINVAL;
+ }
+
+ /* reject writes, which are not page aligned */
+ if (NOTALIGNED (to) || NOTALIGNED(len)) {
+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
return -EINVAL;
}
/* Shift to get page */
page = ((int) to) >> this->page_shift;
- /* Get the starting column */
- col = to & (mtd->oobblock - 1);
-
/* Grab the lock and see if the device is available */
nand_get_chip (this, mtd, FL_WRITING, NULL);
@@ -826,35 +811,20 @@
/* Loop until all data is written */
while (written < len) {
- /*
- * Check, if we have a full page write, then we can
- * use the given buffer, else we have to copy
- */
- if (!col && (len - written) >= mtd->oobblock) {
- this->data_poi = (u_char*) &buf[written];
- cnt = mtd->oobblock;
- } else {
- cnt = 0;
- for (i = col; i < len && i < mtd->oobblock; i++) {
- this->data_buf[i] = buf[written + i];
- cnt++;
- }
- this->data_poi = this->data_buf;
- }
- /* We use the same function for write and writev !) */
+ int cnt = mtd->oobblock;
+ this->data_poi = (u_char*) &buf[written];
+ /* We use the same function for write and writev */
if (eccbuf) {
- ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel);
+ ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel);
oob += mtd->oobsize;
} else
- ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);
+ ret = nand_write_page (mtd, this, page, NULL, oobsel);
if (ret)
goto out;
/* Update written bytes count */
written += cnt;
- /* Next write is aligned */
- col = 0;
/* Increment page address */
page++;
}
@@ -978,7 +948,7 @@
static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count,
loff_t to, size_t * retlen, u_char *eccbuf, int oobsel)
{
- int i, page, col, cnt, len, total_len, ret = 0, written = 0;
+ int i, page, len, total_len, ret = 0, written = 0;
struct nand_chip *this = mtd->priv;
/* Calculate total length of data */
@@ -995,12 +965,15 @@
return -EINVAL;
}
+ /* reject writes, which are not page aligned */
+ if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
+ return -EINVAL;
+ }
+
/* Shift to get page */
page = ((int) to) >> this->page_shift;
- /* Get the starting column */
- col = to & (mtd->oobblock - 1);
-
/* Grab the lock and see if the device is available */
nand_get_chip (this, mtd, FL_WRITING, NULL);
@@ -1016,18 +989,14 @@
}
/* Loop until all iovecs' data has been written */
- cnt = col;
len = 0;
-
while (count) {
/*
- * Check, if we write from offset 0 and if the tuple
- * gives us not enough data for a full page write. Then we
- * can use the iov direct, else we have to copy into
- * data_buf.
+ * Check, if the tuple gives us not enough data for a
+ * full page write. Then we can use the iov direct,
+ * else we have to copy into data_buf.
*/
- if (!cnt && (vecs->iov_len - len) >= mtd->oobblock) {
- cnt = mtd->oobblock;
+ if ((vecs->iov_len - len) >= mtd->oobblock) {
this->data_poi = (u_char *) vecs->iov_base;
this->data_poi += len;
len += mtd->oobblock;
@@ -1042,6 +1011,7 @@
* Read data out of each tuple until we have a full page
* to write or we've read all the tuples.
*/
+ int cnt = 0;
while ((cnt < mtd->oobblock) && count) {
if (vecs->iov_base != NULL && vecs->iov_len) {
this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
@@ -1057,15 +1027,12 @@
}
/* We use the same function for write and writev !) */
- ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);
+ ret = nand_write_page (mtd, this, page, NULL, oobsel);
if (ret)
goto out;
/* Update written bytes count */
- written += (cnt - col);
-
- /* Reset written byte counter and column */
- col = cnt = 0;
+ written += mtd->oobblock;;
/* Increment page address */
page++;
More information about the linux-mtd-cvs
mailing list