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