Ejemplo n.º 1
0
/* Write a chunk (page) of data to NAND.
 *
 * Caller always provides ExtendedTags data which are converted to a more
 * compact (packed) form for storage in NAND.  A mini-ECC runs over the
 * contents of the tags meta-data; used to valid the tags when read.
 *
 *  - Pack ExtendedTags to PackedTags1 form
 *  - Compute mini-ECC for PackedTags1
 *  - Write data and packed tags to NAND.
 *
 * Note: Due to the use of the PackedTags1 meta-data which does not include
 * a full sequence number (as found in the larger PackedTags2 form) it is
 * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
 * discarded and dirty.  This is not ideal: newer NAND parts are supposed
 * to be written just once.  When Yaffs performs this operation, this
 * function is called with a NULL data pointer -- calling MTD write_oob
 * without data is valid usage (2.6.17).
 *
 * Any underlying MTD error results in YAFFS_FAIL.
 * Returns YAFFS_OK or YAFFS_FAIL.
 */
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
	int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
{
	struct mtd_info * mtd = dev->genericDevice;
	int chunkBytes = dev->nDataBytesPerChunk;
	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
	struct mtd_oob_ops ops;
	yaffs_PackedTags1 pt1;
	int retval;

	/* we assume that PackedTags1 and yaffs_Tags are compatible */
	compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
	compile_time_assertion(sizeof(yaffs_Tags) == 8);

	dev->nPageWrites++;

	yaffs_PackTags1(&pt1, etags);
	yaffs_CalcTagsECC((yaffs_Tags *)&pt1);

	/* When deleting a chunk, the upper layer provides only skeletal
	 * etags, one with chunkDeleted set.  However, we need to update the
	 * tags, not erase them completely.  So we use the NAND write property
	 * that only zeroed-bits stick and set tag bytes to all-ones and
	 * zero just the (not) deleted bit.
	 */
#ifndef CONFIG_YAFFS_9BYTE_TAGS
	if (etags->chunkDeleted) {
		memset(&pt1, 0xff, 8);
		/* clear delete status bit to indicate deleted */
		pt1.deleted = 0;
	}
#else
	((__u8 *)&pt1)[8] = 0xff;
	if (etags->chunkDeleted) {
		memset(&pt1, 0xff, 8);
		/* zero pageStatus byte to indicate deleted */
		((__u8 *)&pt1)[8] = 0;
	}
#endif

	memset(&ops, 0, sizeof(ops));
	ops.mode = MTD_OOB_AUTO;
	ops.len = (data) ? chunkBytes : 0;
	ops.ooblen = YTAG1_SIZE;
	ops.datbuf = (__u8 *)data;
	ops.oobbuf = (__u8 *)&pt1;

	retval = mtd->write_oob(mtd, addr, &ops);
	if (retval) {
		yaffs_trace(YAFFS_TRACE_MTD,
			"write_oob failed, chunk %d, mtd error %d\n",
			chunkInNAND, retval);
	}
	return retval ? YAFFS_FAIL : YAFFS_OK;
}
Ejemplo n.º 2
0
/* Write a chunk (page) of data to NAND.
 *
 * Caller always provides ExtendedTags data which are converted to a more
 * compact (packed) form for storage in NAND.  A mini-ECC runs over the
 * contents of the tags meta-data; used to valid the tags when read.
 *
 *  - Pack ExtendedTags to packed_tags1 form
 *  - Compute mini-ECC for packed_tags1
 *  - Write data and packed tags to NAND.
 *
 * Note: Due to the use of the packed_tags1 meta-data which does not include
 * a full sequence number (as found in the larger packed_tags2 form) it is
 * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
 * discarded and dirty.  This is not ideal: newer NAND parts are supposed
 * to be written just once.  When Yaffs performs this operation, this
 * function is called with a NULL data pointer -- calling MTD write_oob
 * without data is valid usage (2.6.17).
 *
 * Any underlying MTD error results in YAFFS_FAIL.
 * Returns YAFFS_OK or YAFFS_FAIL.
 */
int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
			      int nand_chunk, const u8 *data,
			      const struct yaffs_ext_tags *etags)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int chunk_bytes = dev->data_bytes_per_chunk;
	loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
	struct mtd_oob_ops ops;
	struct yaffs_packed_tags1 pt1;
	int retval;

	/* we assume that packed_tags1 and struct yaffs_tags are compatible */
	compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
	compile_time_assertion(sizeof(struct yaffs_tags) == 8);

	yaffs_pack_tags1(&pt1, etags);
	yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);

	/* When deleting a chunk, the upper layer provides only skeletal
	 * etags, one with is_deleted set.  However, we need to update the
	 * tags, not erase them completely.  So we use the NAND write property
	 * that only zeroed-bits stick and set tag bytes to all-ones and
	 * zero just the (not) deleted bit.
	 */

	if(dev->param.tags_9bytes) {
        	((u8 *) &pt1)[8] = 0xff;
        	if (etags->is_deleted) {
		        memset(&pt1, 0xff, 8);
		        /* zero page_status byte to indicate deleted */
		        ((u8 *) &pt1)[8] = 0;
                }
        } else {
        	if (etags->is_deleted) {
	        	memset(&pt1, 0xff, 8);
	        	/* clear delete status bit to indicate deleted */
	        	pt1.deleted = 0;
                }
        }

	memset(&ops, 0, sizeof(ops));
	ops.mode = MTD_OPS_AUTO_OOB;
	ops.len = (data) ? chunk_bytes : 0;
	ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
	ops.datbuf = (u8 *) data;
	ops.oobbuf = (u8 *) &pt1;

	retval = mtd->write_oob(mtd, addr, &ops);
	if (retval) {
		yaffs_trace(YAFFS_TRACE_MTD,
			"write_oob failed, chunk %d, mtd error %d",
			nand_chunk, retval);
	}
	return retval ? YAFFS_FAIL : YAFFS_OK;
}
Ejemplo n.º 3
0
/* Write a chunk (page) of data to NAND.
 *
 * Caller always provides ExtendedTags data which are converted to a more
 * compact (packed) form for storage in NAND.  A mini-ECC runs over the
 * contents of the tags meta-data; used to valid the tags when read.
 *
 *  - Pack ExtendedTags to PackedTags1 form
 *  - Compute mini-ECC for PackedTags1
 *  - Write data and packed tags to NAND.
 *
 * Note: Due to the use of the PackedTags1 meta-data which does not include
 * a full sequence number (as found in the larger PackedTags2 form) it is
 * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
 * discarded and dirty.  This is not ideal: newer NAND parts are supposed
 * to be written just once.  When Yaffs performs this operation, this
 * function is called with a NULL data pointer -- calling MTD write_oob
 * without data is valid usage (2.6.17).
 *
 * Any underlying MTD error results in YAFFS_FAIL.
 * Returns YAFFS_OK or YAFFS_FAIL.
 */
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev,
	int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int chunkBytes = dev->data_bytes_per_chunk;
	loff_t addr = ((loff_t)nand_chunk) * chunkBytes;
	struct mtd_oob_ops ops;
	yaffs_PackedTags1 pt1;
	int retval;

	/* we assume that PackedTags1 and yaffs_tags_t are compatible */
	compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
	compile_time_assertion(sizeof(yaffs_tags_t) == 8);

	yaffs_PackTags1(&pt1, etags);
	yaffs_calc_tags_ecc((yaffs_tags_t *)&pt1);

	/* When deleting a chunk, the upper layer provides only skeletal
	 * etags, one with is_deleted set.  However, we need to update the
	 * tags, not erase them completely.  So we use the NAND write property
	 * that only zeroed-bits stick and set tag bytes to all-ones and
	 * zero just the (not) deleted bit.
	 */
#ifndef CONFIG_YAFFS_9BYTE_TAGS
	if (etags->is_deleted) {
		memset(&pt1, 0xff, 8);
		/* clear delete status bit to indicate deleted */
		pt1.deleted = 0;
	}
#else
	((__u8 *)&pt1)[8] = 0xff;
	if (etags->is_deleted) {
		memset(&pt1, 0xff, 8);
		/* zero page_status byte to indicate deleted */
		((__u8 *)&pt1)[8] = 0;
	}
#endif

	memset(&ops, 0, sizeof(ops));
	ops.mode = MTD_OOB_AUTO;
	ops.len = (data) ? chunkBytes : 0;
	ops.ooblen = YTAG1_SIZE;
	ops.datbuf = (__u8 *)data;
	ops.oobbuf = (__u8 *)&pt1;

	retval = mtd->write_oob(mtd, addr, &ops);
	if (retval) {
		T(YAFFS_TRACE_MTD,
			(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
			nand_chunk, retval));
	}
	return retval ? YAFFS_FAIL : YAFFS_OK;
}
Ejemplo n.º 4
0
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
	int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
{
	struct mtd_info *mtd = dev->genericDevice;
	int chunkBytes = dev->nDataBytesPerChunk;
	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
	struct mtd_oob_ops ops;
	yaffs_PackedTags1 pt1;
	int retval;

	
	compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
	compile_time_assertion(sizeof(yaffs_Tags) == 8);

	yaffs_PackTags1(&pt1, etags);
	yaffs_CalcTagsECC((yaffs_Tags *)&pt1);

	
#ifndef CONFIG_YAFFS_9BYTE_TAGS
	if (etags->chunkDeleted) {
		memset(&pt1, 0xff, 8);
		
		pt1.deleted = 0;
	}
#else
	((__u8 *)&pt1)[8] = 0xff;
	if (etags->chunkDeleted) {
		memset(&pt1, 0xff, 8);
		
		((__u8 *)&pt1)[8] = 0;
	}
#endif

	memset(&ops, 0, sizeof(ops));
	ops.mode = MTD_OOB_AUTO;
	ops.len = (data) ? chunkBytes : 0;
	ops.ooblen = YTAG1_SIZE;
	ops.datbuf = (__u8 *)data;
	ops.oobbuf = (__u8 *)&pt1;

	retval = mtd->write_oob(mtd, addr, &ops);
	if (retval) {
		yaffs_trace(YAFFS_TRACE_MTD,
			"write_oob failed, chunk %d, mtd error %d\n",
			chunkInNAND, retval);
	}
	return retval ? YAFFS_FAIL : YAFFS_OK;
}