/* 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; }
/* 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; }
/* 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; }
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; }