Esempio n. 1
0
void ftl_trim(UINT32 const lba, UINT32 const num_sectors)
{
	ASSERT(num_sectors > 0);

	uart_printf("Num sectors: %u", num_sectors);
	uart_printf("SATA_WBUF_PTR: %u", GETREG(SATA_WBUF_PTR));
	uart_printf("g_ftl_write_buf_id: %u", g_ftl_write_buf_id);

	UINT32 next_write_buf_id = (g_ftl_write_buf_id + num_sectors) % NUM_WR_BUFFERS;

	for (UINT32 i=0;i<num_sectors;i++)
	{
		for (UINT32 j=0;j<512/8;j=j+2)
		{
			UINT32 address = read_dram_32(WR_BUF_PTR(g_ftl_write_buf_id)+j*sizeof(UINT32));
			UINT32 reg2 = read_dram_32(WR_BUF_PTR(g_ftl_write_buf_id)+(j+1)*sizeof(UINT32));
			UINT32 count = reg2 & 0xFFFF0000; // Count stored in the first four words.

			// If count is zero. We continue, but also, if address is 48bit.
			// We shouldn't get these unless it is an error.
			if (count == 0 || (reg2 & 0x0000FFFF) > 0) //
				continue;

//			uart_print_hex(address);
//			uart_print_hex(count);
		}

		g_ftl_write_buf_id = (g_ftl_write_buf_id + 1) % NUM_WR_BUFFERS;
	}
	SETREG(BM_STACK_WRSET, next_write_buf_id);	// change bm_read_limit
	SETREG(BM_STACK_RESET, 0x02);				// change bm_read_limi
}
void checkNoChunksAreValid(UINT32 bank, UINT32 lbn)
{
    for(UINT32 page=0; page<PAGES_PER_BLK; ++page)
    {
        for (UINT32 chunk=0; chunk<CHUNKS_PER_PAGE; ++chunk)
        {
            UINT32 logChunkAddr = (bank*LOG_BLK_PER_BANK*CHUNKS_PER_BLK) + (lbn*CHUNKS_PER_BLK) + (page*CHUNKS_PER_PAGE) + chunk;
            UINT32 i = mem_search_equ_dram_4_bytes(CHUNKS_MAP_TABLE_ADDR, CHUNKS_MAP_TABLE_BYTES/4, logChunkAddr);
            if (i<CHUNKS_MAP_TABLE_BYTES/4)
            {
                uart_print_level_1("ERROR: after GC not all chunks are invalid. bank=");
                uart_print_level_1_int(bank);
                uart_print_level_1(" lbn=");
                uart_print_level_1_int(lbn);
                uart_print_level_1(" page=");
                uart_print_level_1_int(page);
                uart_print_level_1(" chunk=");
                uart_print_level_1_int(chunk);
                uart_print_level_1(". dataLpn=");
                uart_print_level_1_int(i/CHUNKS_PER_PAGE);
                uart_print_level_1("\r\n");
                if (read_dram_32(ChunksMapTable(i/CHUNKS_PER_PAGE, i%CHUNKS_PER_PAGE)) != logChunkAddr )
                {
                    uart_print_level_1("Nevermind\r\n");
                }
            }
        }
    }
}
Esempio n. 3
0
static UINT32 get_psn(UINT32 const lba)		//added by RED
{   
	//UINT32 src = SMT_ADDR + (lba * sizeof(UINT32));
	//UINT32 dst = (UINT32)g_psn_read;
	//UINT32 size = sizeof(UINT32) * totals;
	//mem_copy(dst,src,size);
	UINT32 dst, bank, block, sector;
	UINT32 sectors_per_mblk = (SECTORS_PER_BANK + SMT_BANK_NUM - 1) / SMT_BANK_NUM;

	bank = lba / SECTORS_PER_BANK;
	block = (lba % SECTORS_PER_BANK)  / (sectors_per_mblk);
	sector = (lba % SECTORS_PER_BANK) % (sectors_per_mblk);

	dst = smt_piece_map[bank * SMT_BANK_NUM + block];
	if( dst == (UINT32)-1 )
	{
#if OPTION_FTL_TEST == 1
		num_miss++;
#endif
		load_smt_piece( bank * SMT_BANK_NUM + block);
		dst = smt_piece_map[bank * SMT_BANK_NUM + block];
		while(_BSP_FSM(g_bank_to_wait) != BANK_IDLE);
	}
	dst = SMT_ADDR + (SMT_PIECE_BYTES * dst) + (sector * sizeof(UINT32));
	return read_dram_32((UINT32*)dst);

}
Esempio n. 4
0
static void overwriteCompletePageInOwLog() {
#if DetailedOwStats == 1
    uart_print_level_1("-\r\n");
#endif
    uart_print("overwriteCompletePageInOwLog\r\n");
    #if MeasureDetailedOverwrite
    start_interval_measurement(TIMER_CH3, TIMER_PRESCALE_0);
    #endif
    chooseNewBank_();
    manageOldCompletePage();
    UINT32 newLogLpn = getOWLpn(bank_);
    UINT32 lbn = LogPageToLogBlk(newLogLpn);
    UINT32 vBlk = get_log_vbn(bank_, lbn);
    UINT32 pageOffset = LogPageToOffset(newLogLpn);
    nand_page_ptprogram_from_host(bank_, vBlk, pageOffset, 0, SECTORS_PER_PAGE);
    increaseOwCounter(bank_, lbn, pageOffset);
    #if MeasureOwEfficiency
    write_dram_32(OwEffBuf(bank_, LogPageToLogBlk(newLogLpn)), read_dram_32(OwEffBuf(bank_, LogPageToLogBlk(newLogLpn))) + SECTORS_PER_PAGE);
    #endif
    for(UINT32 i=0; i<CHUNKS_PER_PAGE; i++)
    {
        write_dram_32(chunkInLpnsList(OWCtrl[bank_].lpnsListPtr, LogPageToOffset(newLogLpn), i), lpn_);
        write_dram_32(ChunksMapTable(lpn_, i), ( (bank_ * LOG_BLK_PER_BANK * CHUNKS_PER_BLK) + (newLogLpn * CHUNKS_PER_PAGE) + i ) | StartOwLogLpn);
    }
    increaseOWLpn(bank_);
    #if MeasureDetailedOverwrite
    UINT32 timerValue=GET_TIMER_VALUE(TIMER_CH3);
    UINT32 nTicks = 0xFFFFFFFF - timerValue;
    uart_print_level_2("OPN0 "); uart_print_level_2_int(nTicks); uart_print_level_2("\r\n");
    #endif
}
Esempio n. 5
0
/* NOTE: This function calls rebuildPageToFtlBuf with GcMode, therefore the valid chunks counters of old blocks are already managed.
 * Do not call manageOldChunks before calling this!
 */
static void appendPageToSWBlock (const UINT32 dataLpn, const UINT32 sectOffset, const UINT32 nSects)
{
    uart_print("appendPageToSWBlock dataLpn="); uart_print_int(dataLpn);
    uart_print(", sectOffset="); uart_print_int(sectOffset);
    uart_print(", nSects="); uart_print_int(nSects); uart_print("\r\n");
    UINT32 nSectsToWrite = SECTORS_PER_PAGE - sectOffset;
    UINT32 logLpn = getSWLpn(bank_);
    UINT32 vBlk = get_log_vbn(bank_, LogPageToLogBlk(logLpn));
    UINT32 dst = FTL_BUF(0) + (sectOffset*BYTES_PER_SECTOR);
    UINT32 src = WR_BUF_PTR(g_ftl_write_buf_id)+(sectOffset*BYTES_PER_SECTOR);
    rebuildPageToFtlBuf(dataLpn, 0, SECTORS_PER_PAGE, GcMode); // Rebuild rest of the page in FTL buffer (rebuild entire page to be sure that all chunks are correctly garbage collected, especially if they are in DRAM)
    //waitBusyBank(bank_);
    flash_finish();
    mem_copy(dst, src, nSectsToWrite * BYTES_PER_SECTOR);                                       // Fill FTL buffer with new data
    //TODO: this program shouldn't be sincronous, need a global variable storing last bank writing data from FTL_BUF(0)
    nand_page_program(bank_, vBlk, LogPageToOffset(logLpn), FTL_BUF(0), RETURN_WHEN_DONE);      // Write FTL buffer to the next sequential page
    UINT32 chunkIdx;
    for(chunkIdx=0; chunkIdx<sectOffset / SECTORS_PER_CHUNK; ++chunkIdx)
    { // For sector before the start of new data we update only if previously there was some valid data, which is now in the new page, otherwise we insert invalid in the lpns list to speed up GC later
        if (ChunksMapTable(dataLpn, chunkIdx) > DRAM_BASE + DRAM_SIZE)
        {
            uart_print_level_1("ERROR in appendPageToSWBlk 1: reading above DRAM address space\r\n");
        }
        if (read_dram_32(ChunksMapTable(dataLpn, chunkIdx)) != INVALID)
        {
            UINT32 lChunkAddr = (logLpn * CHUNKS_PER_PAGE) + chunkIdx;
            if((chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx)) >=(DRAM_BASE + DRAM_SIZE))
            {
                uart_print_level_1("ERROR in write::appendPageToSWBlk 1: writing to "); uart_print_level_1_int(chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx)); uart_print_level_1("\r\n");
            }
            write_dram_32(chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx), dataLpn);
            write_dram_32(ChunksMapTable(dataLpn, chunkIdx), (bank_ * LOG_BLK_PER_BANK * CHUNKS_PER_BLK) + lChunkAddr);
        }
        else
        { //Decrement valid chunks in the blk we're going to write in because we inserted null data
            if((chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx)) >=(DRAM_BASE + DRAM_SIZE))
            {
                uart_print_level_1("ERROR in write::appendPageToSWBlk 2: writing to "); uart_print_level_1_int(chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx)); uart_print_level_1("\r\n");
            }
            write_dram_32(chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx), INVALID);
            decrementValidChunks(&heapDataWrite, bank_, LogPageToLogBlk(logLpn));
        }
    }
    for( ; chunkIdx < CHUNKS_PER_PAGE; ++chunkIdx)
    { // The new sectors are instead all valid, therefore we don't bother checking if they were valid before
            UINT32 lChunkAddr = (logLpn * CHUNKS_PER_PAGE) + chunkIdx;
            if((chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx)) >=(DRAM_BASE + DRAM_SIZE))
            {
                uart_print_level_1("ERROR in write::appendPageToSWBlk 3: writing to "); uart_print_level_1_int(chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx)); uart_print_level_1("\r\n");
            }
            write_dram_32(chunkInLpnsList(SWCtrl[bank_].lpnsListPtr, LogPageToOffset(logLpn), chunkIdx), dataLpn);
            write_dram_32(ChunksMapTable(dataLpn, chunkIdx), (bank_ * LOG_BLK_PER_BANK * CHUNKS_PER_BLK) + lChunkAddr);
    }
    SWCtrl[bank_].nextDataLpn=dataLpn+1;
    increaseSWLpn(bank_);
    g_ftl_write_buf_id = (g_ftl_write_buf_id + 1) % NUM_WR_BUFFERS;
    SETREG (BM_STACK_WRSET, g_ftl_write_buf_id);
    SETREG (BM_STACK_RESET, 0x01);
}
Esempio n. 6
0
// get vpn from PAGE_MAP
static UINT32 get_vpn(UINT32 const lpn)
{
	if(IS_WRITE)
	{
		get_v_w++;
	}
	else
	{
		get_v++;
	}
	UINT32 index;
	for(index = 0; index < CMT_SIZE; index++)
	{
		if(cmt[index].lpn == lpn)
		{
			if(IS_WRITE)
				get_v_w_hit++;
			else
				cmt_r_hit++;
			return SET_CLEAN(cmt[index].vpn);
		}
		else if(cmt[index].lpn == INVALID)
			return 0;
	}
	/*
	 * not in CMT
	 * now select an victim
	 */
	evict_mapping();
	/*
	 * now, cmt[cmt_hand] is a victim
	 */
	UINT32 gtd_index;
	UINT32 mapping_bank = get_num_bank(lpn);

	UINT32 offset_in_bank = lpn / NUM_BANKS;
	UINT32 offset_in_page = offset_in_bank % MAPPINGS_PER_PAGE;
	gtd_index = offset_in_bank / MAPPINGS_PER_PAGE;
	UINT32 mapping_vpn = gtd[mapping_bank][gtd_index];

	if(mapping_vpn == INVALID)
	{
		return NULL;
	}

	map_read++;
	nand_page_read(mapping_bank,
			mapping_vpn / PAGES_PER_BLK,
			mapping_vpn % PAGES_PER_BLK,
			TRANS_BUF(mapping_bank));
	cmt[cmt_hand].lpn = lpn;
	cmt[cmt_hand].vpn = read_dram_32(TRANS_BUF(mapping_bank) + sizeof(UINT32) * offset_in_page);
	cmt[cmt_hand].sc = TRUE;

	UINT32 ret = SET_CLEAN(cmt[cmt_hand].vpn);
	cmt_hand = (cmt_hand + 1) % CMT_SIZE;
	return ret;
}
Esempio n. 7
0
static UINT8 oldVersionIsInOwLogInOrder()
{
    uart_print("oldVersionIsInOwLogInOrder\r\n");
    UINT32 firstChunk = sectOffset_ / SECTORS_PER_CHUNK;
    UINT32 lastChunk = (sectOffset_ + nSects_ - 1) / SECTORS_PER_CHUNK;
    UINT32 chunk = read_dram_32(ChunksMapTable(lpn_, firstChunk));
    if (findChunkLocation(chunk) == FlashOwLog)
    {
        chunk = chunk & 0x7FFFFFFF;
        if (ChunkToChunkOffset(chunk) != firstChunk) return FALSE;
        UINT32 chunkOffsetInBank = ChunkToChunkOffsetInBank(chunk);
        UINT32 bank = ChunkToBank(chunk);
        for (int i = firstChunk+1; i<=lastChunk; i++)
        {
            chunk = read_dram_32(ChunksMapTable(lpn_, i));
            if (findChunkLocation(chunk) == FlashOwLog)
            {
                chunk = chunk & 0x7FFFFFFF;
                if (ChunkToBank(chunk) != bank)
                {
                    uart_print("Not in order\r\n");
                    return FALSE;
                }
                if (ChunkToChunkOffsetInBank(chunk) != chunkOffsetInBank+1)
                {
                    uart_print("Not in order\r\n");
                    return FALSE;
                }
                chunkOffsetInBank++;
            }
            else
            {
                uart_print("Not in order\r\n");
                return FALSE;
            }
        }
        uart_print("In order\r\n");
        return TRUE;
    }
    else
    {
        uart_print("Not in order\r\n");
        return FALSE;
    }
}
Esempio n. 8
0
/* Completely invalid every metadata related to the chunk, because no GC can happen before the new page written since it is a complete page write */
static void manageOldChunkForCompletePageWrite(int chunkIdx)
{
    uart_print("manageOldChunkForCompletePageWrite\r\n");
    //UINT32 oldChunkAddr = getChunkAddr(node_, chunkIdx);
    if (ChunksMapTable(lpn_, chunkIdx) > DRAM_BASE + DRAM_SIZE)
    {
        uart_print_level_1("ERROR in manageOldChunkForCompletePageWrite 1: reading above DRAM address space\r\n");
    }
    UINT32 oldChunkAddr = read_dram_32(ChunksMapTable(lpn_, chunkIdx));
    switch (findChunkLocation(oldChunkAddr))
    {
        case Invalid:
        {
            uart_print(" invalid\r\n");
            return;
        }
        case FlashWLog:
        {
            uart_print(" in w log\r\n");
            UINT32 oldChunkBank = ChunkToBank(oldChunkAddr);
            decrementValidChunks(&heapDataWrite, oldChunkBank, ChunkToLbn(oldChunkAddr));
            return;
        }
        case DRAMWLog:
        {
            uart_print(" in w DRAM buf\r\n");
            UINT32 oldChunkBank = ChunkToBank(oldChunkAddr);
            logBufMeta[oldChunkBank].dataLpn[oldChunkAddr % CHUNKS_PER_PAGE]=INVALID;
            return;
        }
#if Overwrite
        case DRAMOwLog:
        {
            uart_print(" in ow DRAM buf\r\n");
            oldChunkAddr = oldChunkAddr & 0x7FFFFFFF;
            UINT32 oldChunkBank = ChunkToBank(oldChunkAddr);
            owLogBufMeta[oldChunkBank].dataLpn[oldChunkAddr % CHUNKS_PER_PAGE]=INVALID;
            return;
        }
        case FlashOwLog:
        {
            uart_print(" in ow log\r\n");
            oldChunkAddr = oldChunkAddr & 0x7FFFFFFF;
            UINT32 oldChunkBank = ChunkToBank(oldChunkAddr);
            decrementValidChunks(&heapDataOverwrite, oldChunkBank, ChunkToLbn(oldChunkAddr));
            return;
        }
#endif
    }
}
Esempio n. 9
0
static void overwriteChunkOldInOwLog(UINT32 chunkAddr)
{
    //uart_print_level_1("22 ");
    uart_print("overwriteChunkOldInOwLog\r\n");
    UINT32 nSectsToWrite = (((sectOffset_ % SECTORS_PER_CHUNK) + remainingSects_) < SECTORS_PER_CHUNK) ?     remainingSects_ :
                                                            (SECTORS_PER_CHUNK - (sectOffset_ % SECTORS_PER_CHUNK));
    UINT32 bank = ChunkToBank(chunkAddr);
    UINT32 lbn = ChunkToLbn(chunkAddr);
    UINT32 vbn = get_log_vbn(bank, lbn);
    UINT32 pageOffset = ChunkToPageOffset(chunkAddr);
    if (readOwCounter(bank, lbn, pageOffset) < OwLimit)
    { // Can overwrite in place
        UINT32 sectOffset = ChunkToSectOffset(chunkAddr) + (sectOffset_ % SECTORS_PER_CHUNK);
        //UINT32 src = WR_BUF_PTR(g_ftl_write_buf_id) + (sectOffset_ * BYTES_PER_SECTOR) - (sectOffset * BYTES_PER_SECTOR); // startBuf + srcOffset - dstOffset
        if (lastBankUsingFtlBuf1 != INVALID)
        {
            waitBusyBank(lastBankUsingFtlBuf1);
        }
        mem_copy(FTL_BUF(1)+(sectOffset_*BYTES_PER_SECTOR), WR_BUF_PTR(g_ftl_write_buf_id) + (sectOffset_*BYTES_PER_SECTOR), nSectsToWrite*BYTES_PER_SECTOR);
        UINT32 src = FTL_BUF(1) + (sectOffset_ * BYTES_PER_SECTOR) - (sectOffset * BYTES_PER_SECTOR); // startBuf + srcOffset - dstOffset
        lastBankUsingFtlBuf1 = bank;
        nand_page_ptprogram(bank, vbn, pageOffset, sectOffset, nSectsToWrite, src, RETURN_ON_ISSUE);
        increaseOwCounter(bank, lbn, pageOffset);
    }
    else
    { // Need a new page
        if (nSectsToWrite == SECTORS_PER_CHUNK)
        { // Write chunk in ow log and decrease valid chunks in previous ow blk
            decrementValidChunks(&heapDataOverwrite, bank, lbn);
            overwriteCompleteChunkNew();
        }
        else
        { // Must read old chunk and update in ow log
            decrementValidChunks(&heapDataOverwrite, bank, lbn);
            overwritePartialChunkWhenOldChunkIsInExhaustedOWLog(nSectsToWrite, chunkAddr);
        }
        updateOwDramBufMetadata();
        updateOwChunkPtr();
    }
    #if MeasureOwEfficiency
    write_dram_32(OwEffBuf(bank_, ChunkToLbn(chunkAddr)), read_dram_32(OwEffBuf(bank_, ChunkToLbn(chunkAddr))) + nSectsToWrite);
    #endif
    sectOffset_ += nSectsToWrite;
    remainingSects_ -= nSectsToWrite;
}
Esempio n. 10
0
static UINT32 get_psn(UINT32 const lba)		//added by RED
{   
	//UINT32 src = SMT_ADDR + (lba * sizeof(UINT32));
	//UINT32 dst = (UINT32)g_psn_read;
	//UINT32 size = sizeof(UINT32) * totals;
	//mem_copy(dst,src,size);
	UINT32 dst, bank, block, sector;

	bank = lba / SECTORS_PER_BANK;
	block = (lba % SECTORS_PER_BANK ) / (SECTORS_PER_PAGE * PAGES_PER_VBLK * ((VBLKS_PER_BANK + NUM_BANKS_MAX - 1) / NUM_BANKS_MAX));
	sector = (lba % SECTORS_PER_BANK ) % (SECTORS_PER_PAGE * PAGES_PER_VBLK * ((VBLKS_PER_BANK + NUM_BANKS_MAX - 1) / NUM_BANKS_MAX));
	if( (smt_dram_bit[ bank ] & (1 << block)) == 0)
	{
		load_smt_piece( bank * NUM_BANKS_MAX + block);
	}
	dst = smt_piece_map[bank * NUM_BANKS_MAX + block];
	dst = SMT_ADDR + (SMT_PIECE_BYTES * dst) + (sector * sizeof(UINT32));
	return read_dram_32((UINT32*)dst);

}
Esempio n. 11
0
static void flushOwLogBuffer()
{
    uart_print("bank "); uart_print_int(bank_);
    uart_print(" flushOwLogBuffer\r\n");
    UINT32 newLogLpn = getOWLpn(bank_);
    if (newLogLpn == INVALID)
    {
        uart_print_level_1("ERROR in flushOwLogBuffer: got INVALID lpn\r\n");
        while(1);
    }
    uart_print("new log lpn="); uart_print_int(newLogLpn); uart_print("\r\n");
    UINT32 lbn = LogPageToLogBlk(newLogLpn);
    UINT32 vBlk = get_log_vbn(bank_, lbn);
    UINT32 pageOffset = LogPageToOffset(newLogLpn);
    nand_page_program(bank_, vBlk, pageOffset, OW_LOG_BUF(bank_), RETURN_ON_ISSUE);
    increaseOwCounter(bank_, lbn, pageOffset);
#if MeasureOwEfficiency
    write_dram_32(OwEffBuf(bank_, LogPageToLogBlk(newLogLpn)), read_dram_32(OwEffBuf(bank_, LogPageToLogBlk(newLogLpn))) + SECTORS_PER_PAGE);
#endif
    for(UINT32 i=0; i<CHUNKS_PER_PAGE; i++)
    {
        uart_print("Chunk "); uart_print_int(i); uart_print(" ");
        UINT32 lChunkAddr = ( (bank_ * LOG_BLK_PER_BANK * CHUNKS_PER_BLK) + (newLogLpn * CHUNKS_PER_PAGE) + i );
        uart_print("lChunkAddr "); uart_print_int(lChunkAddr); uart_print(" ");
        lChunkAddr = lChunkAddr | StartOwLogLpn;
        uart_print("full "); uart_print_int(lChunkAddr); uart_print("\r\n");
        write_dram_32(chunkInLpnsList(OWCtrl[bank_].lpnsListPtr, LogPageToOffset(newLogLpn), i), owLogBufMeta[bank_].dataLpn[i]);
        if (owLogBufMeta[bank_].dataLpn[i] != INVALID)
        {
            write_dram_32(ChunksMapTable(owLogBufMeta[bank_].dataLpn[i], owLogBufMeta[bank_].chunkIdx[i]), lChunkAddr);
        }
        else
        {
            decrementValidChunks(&heapDataOverwrite, bank_, LogPageToLogBlk(newLogLpn));
        }
    }
    increaseOWLpn(bank_);
}
Esempio n. 12
0
static UINT32 get_psn(UINT32 const lba)		//added by RED
{   
	//UINT32 src = SMT_ADDR + (lba * sizeof(UINT32));
	//UINT32 dst = (UINT32)g_psn_read;
	//UINT32 size = sizeof(UINT32) * totals;
	//mem_copy(dst,src,size);
	UINT32 dst, bank, block, sector;
	UINT32 sectors_per_mblk = (SECTORS_PER_BANK + NUM_BANKS_MAX - 1) / NUM_BANKS_MAX;

	bank = lba / SECTORS_PER_BANK;
	block = (lba % SECTORS_PER_BANK)  / (sectors_per_mblk);
	sector = (lba % SECTORS_PER_BANK) % (sectors_per_mblk);

	dst = smt_piece_map[bank * NUM_BANKS_MAX + block];
	if( dst == (UINT32)-1 )
	{
		load_smt_piece( bank * NUM_BANKS_MAX + block);
		dst = smt_piece_map[bank * NUM_BANKS_MAX + block];
	}
	dst = SMT_ADDR + (SMT_PIECE_BYTES * dst) + (sector * sizeof(UINT32));
	return read_dram_32((UINT32*)dst);

}
Esempio n. 13
0
static void setupFlashPageRead(UINT32 * chunksInPage, UINT32 * srcChunkByteOffsets, UINT32 * chunkIdxs, UINT8 *decreaseInOW)
{
    uart_print("setupFlashPageRead\r\n");
    for (UINT32 i=chunkIdx_+1; i<lastChunk_; i++)
    {
        uart_print("next chunk: "); uart_print_int(i); uart_print("\r\n");
        if (chunksDone_[i] == 0)
        {
            //UINT32 nextChunkAddr = getChunkAddr(node_, i);
            if (ChunksMapTable(lpn_, i) > DRAM_BASE + DRAM_SIZE)
            {
                uart_print_level_1("ERROR in setupFlashPageRead 1: reading above DRAM address space\r\n");
            }
            UINT32 nextChunkAddr = read_dram_32(ChunksMapTable(lpn_, i));
            switch (findChunkLocation(nextChunkAddr))
            {
                case Invalid:
                {
                    uart_print(" not valid\r\n");
                    continue;
                    break;
                }
                case FlashWLog:
                {
                    uart_print(" in flash w log\r\n");
                    if (chunksInSameFlashPage(oldChunkAddr_, nextChunkAddr))
                    {
                        uart_print(" in same flash log\r\n");
                        srcChunkByteOffsets[*chunksInPage]=ChunkToSectOffset(nextChunkAddr)*BYTES_PER_SECTOR;
                        chunkIdxs[*chunksInPage]=i;
                        decreaseInOW[*chunksInPage]=FALSE;
                        (*chunksInPage)++;
                    }
                    else
                    {
                        uart_print(" in different flash log\r\n");
                    }
                    continue;
                    break;
                }
                case DRAMWLog:
                {
                    uart_print(" in dram w log\r\n");
                    continue;
                    break;
                }
#if Overwrite
                case DRAMOwLog:
                {
                    uart_print(" in dram ow log\r\n");
                    continue;
                    break;
                }
                case FlashOwLog:
                {
                    nextChunkAddr = nextChunkAddr & 0x7FFFFFFF;
                    if (chunksInSameFlashPage(oldChunkAddr_, nextChunkAddr)) {
                        uart_print(" in same flash log\r\n");
                        srcChunkByteOffsets[*chunksInPage]=ChunkToSectOffset(nextChunkAddr)*BYTES_PER_SECTOR;
                        chunkIdxs[*chunksInPage]=i;
                        decreaseInOW[*chunksInPage]=TRUE;
                        (*chunksInPage)++;
                    }
                    else
                    {
                        uart_print(" in different flash log\r\n");
                    }
                    break;
                }
#endif
            }
        }
        else
        {
            uart_print(" already done\r\n");
        }
    }
}
Esempio n. 14
0
static void tc_write_rand(const UINT32 start_lsn, const UINT32 io_num, const UINT32 sector_size)
{
    UINT32 i, j, wr_buf_addr, rd_buf_addr, data, r_data;
    UINT32 lba, num_sectors = sector_size;
    UINT32 io_cnt = io_num;

    /* UINT32 volatile g_barrier = 0; while (g_barrier == 0); */
    led(0);
    srand(RANDOM_SEED);

    for (UINT32 loop = 0; loop < 1; loop++) {
        wr_buf_addr = WR_BUF_ADDR;
        data = 0;
        uart_printf("test loop cnt: %d", loop);

        for (i = 0; i < io_cnt; i++) {
            do {
                lba = rand() % IO_LIMIT;
            }while(lba + num_sectors >= IO_LIMIT);

            wr_buf_addr = WR_BUF_PTR(g_ftl_write_buf_id) + ((lba % SECTORS_PER_PAGE) * BYTES_PER_SECTOR);
            r_data = data;

            for (j = 0; j < num_sectors; j++) {
                mem_set_dram(wr_buf_addr, data, BYTES_PER_SECTOR);

                wr_buf_addr += BYTES_PER_SECTOR;

                if (wr_buf_addr >= WR_BUF_ADDR + WR_BUF_BYTES) {
                    wr_buf_addr = WR_BUF_ADDR;
                }
                data++;
            }
/*             ptimer_start(); */
            ftl_write(lba, num_sectors);
/*             ptimer_stop_and_uart_print(); */
            rd_buf_addr = RD_BUF_PTR(g_ftl_read_buf_id) + ((lba % SECTORS_PER_PAGE) * BYTES_PER_SECTOR);
/*             ptimer_start(); */
            ftl_read(lba, num_sectors);
/*             ptimer_stop_and_uart_print(); */

            flash_finish();

            for (j = 0; j < num_sectors; j++) {
                UINT32 sample = read_dram_32(rd_buf_addr);

                if (sample != r_data) {
                    uart_printf("ftl test fail...io#: %d, %d", lba, num_sectors);
                    uart_printf("sample data %d should be %d", sample, r_data);
                    led_blink();
                }
                rd_buf_addr += BYTES_PER_SECTOR;

                if (rd_buf_addr >= RD_BUF_ADDR + RD_BUF_BYTES) {
                    rd_buf_addr = RD_BUF_ADDR;
                }
                r_data++;
            }
        } // end for
    }
    ftl_flush();
}
Esempio n. 15
0
static void tc_write_seq(const UINT32 start_lsn, const UINT32 io_num, const UINT32 sector_size)
{
    UINT32 i, j, wr_buf_addr, rd_buf_addr, data;
    UINT32 lba, num_sectors = sector_size;
    UINT32 io_cnt = io_num;
    UINT32 const start_lba = start_lsn;

    /* UINT32 volatile g_barrier = 0; while (g_barrier == 0); */
    led(0);

    // STEP 1 - write
    for (UINT32 loop = 0; loop < 5; loop++)
    {
        wr_buf_addr = WR_BUF_ADDR;
        data = 0;
        lba  = start_lba;

        uart_print_32(loop); uart_print("");

        for (i = 0; i < io_cnt; i++)
        {
            wr_buf_addr = WR_BUF_PTR(g_ftl_write_buf_id) + ((lba % SECTORS_PER_PAGE) * BYTES_PER_SECTOR);
            for (j = 0; j < num_sectors; j++)
            {
                mem_set_dram(wr_buf_addr, data, BYTES_PER_SECTOR);

                wr_buf_addr += BYTES_PER_SECTOR;

                if (wr_buf_addr >= WR_BUF_ADDR + WR_BUF_BYTES)
                {
                    wr_buf_addr = WR_BUF_ADDR;
                }
                data++;
            }
	    if( i == 0x0000081C)
		    i = i;
            ptimer_start();
            ftl_write(lba, num_sectors);
            ptimer_stop_and_uart_print();

            lba += num_sectors;

            if (lba >= (UINT32)NUM_LSECTORS)
            {
                uart_print("adjust lba because of out of lba");
                lba = 0;
            }
        }

        // STEP 2 - read and verify
        rd_buf_addr = RD_BUF_ADDR;
        data = 0;
        lba  = start_lba;
        num_sectors = MIN(num_sectors, NUM_RD_BUFFERS * SECTORS_PER_PAGE);

        for (i = 0; i < io_cnt; i++)
        {
            rd_buf_addr = RD_BUF_PTR(g_ftl_read_buf_id) + ((lba % SECTORS_PER_PAGE) * BYTES_PER_SECTOR);
            /* ptimer_start(); */
	    if( i == 0x0000081C)
		    i = i;
            ftl_read(lba, num_sectors);

            flash_finish();
            /* ptimer_stop_and_uart_print(); */

            for (j = 0; j < num_sectors; j++)
            {
                UINT32 sample = read_dram_32(rd_buf_addr);

                if (sample != data)
                {
                    uart_printf("ftl test fail...io#: %d, %d", lba, num_sectors);
                    uart_printf("sample data %d should be %d", sample, data);
                    led_blink();
                }

                rd_buf_addr += BYTES_PER_SECTOR;

                if (rd_buf_addr >= RD_BUF_ADDR + RD_BUF_BYTES)
                {
                    rd_buf_addr = RD_BUF_ADDR;
                }
                data++;
            }

            lba += num_sectors;

            if (lba >= IO_LIMIT + num_sectors)
            {
                lba = 0;
            }
        }
    }
    ftl_flush();
}
Esempio n. 16
0
static void writeChunkOld()
{
    //uart_print_level_1("7 ");
    uart_print("writeChunkOld\r\n");
    UINT32 nSectsToWrite = (((sectOffset_ % SECTORS_PER_CHUNK) + remainingSects_) < SECTORS_PER_CHUNK) ? remainingSects_ : (SECTORS_PER_CHUNK - (sectOffset_ % SECTORS_PER_CHUNK));
    UINT32 chunkIdx = sectOffset_ / SECTORS_PER_CHUNK;
    if (ChunksMapTable(lpn_, chunkIdx) > DRAM_BASE + DRAM_SIZE)
    {
        uart_print_level_1("ERROR in writeChunkOld 1: reading above DRAM address space\r\n");
    }
    UINT32 oldChunkAddr = read_dram_32(ChunksMapTable(lpn_, chunkIdx));
    uart_print("Old chunk is ");
    switch (findChunkLocation(oldChunkAddr))
    {
        case Invalid:
        {
            uart_print(" invalid\r\n");

            writeChunkNew(nSectsToWrite);
            updateDramBufMetadata();
            updateChunkPtr();
            sectOffset_ += nSectsToWrite;
            remainingSects_ -= nSectsToWrite;
            return;

            break;
        }
        case FlashWLog:
        {
            uart_print(" in w log\r\n");
            if (nSectsToWrite == SECTORS_PER_CHUNK)
            {
                writeChunkNew(nSectsToWrite);
            }
            else
            {
                writePartialChunkWhenOldChunkIsInFlashLog(nSectsToWrite, oldChunkAddr);
            }
            UINT32 oldChunkBank = ChunkToBank(oldChunkAddr);
            decrementValidChunks(&heapDataWrite, oldChunkBank, ChunkToLbn(oldChunkAddr));
            updateDramBufMetadata();
            updateChunkPtr();
            sectOffset_ += nSectsToWrite;
            remainingSects_ -= nSectsToWrite;
            return;
            break;
        }
        case DRAMWLog:
        {
            uart_print(" in w DRAM buf\r\n");
            writePartialChunkWhenOldIsInWBuf(nSectsToWrite, oldChunkAddr);
            sectOffset_ += nSectsToWrite;
            remainingSects_ -= nSectsToWrite;
            break;
        }
#if Overwrite
        case DRAMOwLog:
        {
            uart_print(" in ow DRAM buf\r\n");
            oldChunkAddr = oldChunkAddr & 0x7FFFFFFF;
            if (nSectsToWrite == SECTORS_PER_CHUNK)
            {
                writeChunkNew(nSectsToWrite);
            }
            else
            {
                writePartialChunkWhenOldIsInOWBuf(nSectsToWrite, oldChunkAddr);
            }
            UINT32 oldChunkBank = ChunkToBank(oldChunkAddr);
            owLogBufMeta[oldChunkBank].dataLpn[oldChunkAddr % CHUNKS_PER_PAGE]=INVALID;
            updateDramBufMetadata();
            updateChunkPtr();
            sectOffset_ += nSectsToWrite;
            remainingSects_ -= nSectsToWrite;
            break;
        }
        case FlashOwLog:
        {
            uart_print(" in ow log\r\n");
            oldChunkAddr = oldChunkAddr & 0x7FFFFFFF;
            if (nSectsToWrite == SECTORS_PER_CHUNK)
            {
                writeChunkNew(nSectsToWrite);
            }
            else
            {
                writePartialChunkWhenOldChunkIsInFlashLog(nSectsToWrite, oldChunkAddr);
            }
            UINT32 oldChunkBank = ChunkToBank(oldChunkAddr);
            decrementValidChunks(&heapDataOverwrite, oldChunkBank, ChunkToLbn(oldChunkAddr));
            updateDramBufMetadata();
            updateChunkPtr();
            sectOffset_ += nSectsToWrite;
            remainingSects_ -= nSectsToWrite;
            break;
        }
#endif
    }
}
Esempio n. 17
0
static void overwritePageOldInOrderInOwLog()
{
    #if MeasureDetailedOverwrite
    start_interval_measurement(TIMER_CH3, TIMER_PRESCALE_0);
    #endif
    uart_print("overwritePageOldInOrderInOwLog\r\n");
    UINT32 firstChunk = sectOffset_ / SECTORS_PER_CHUNK;
    UINT32 chunk = read_dram_32(ChunksMapTable(lpn_, firstChunk));
    chunk = chunk & 0x7FFFFFFF;
    UINT32 bank = ChunkToBank(chunk);
    UINT32 lbn = ChunkToLbn(chunk);
    UINT32 vBlk = get_log_vbn(bank, lbn);
    UINT32 pageOffset = ChunkToPageOffset(chunk);
    if(readOwCounter(bank, lbn, pageOffset) < OwLimit)
    {
#if DetailedOwStats == 1
        uart_print_level_1("*\r\n");
#endif
        uart_print("Can overwrite in place\r\n");
        nand_page_ptprogram_from_host(bank, vBlk, pageOffset, sectOffset_, nSects_);
        increaseOwCounter(bank, lbn, pageOffset);
        #if MeasureOwEfficiency
        write_dram_32(OwEffBuf(bank_, ChunkToLbn(chunk)), read_dram_32(OwEffBuf(bank_, ChunkToLbn(chunk))) + nSects_);
        #endif
    }
    else
    {
        uart_print("Exceeding limit, must find a new page\r\n");
        if (remainingSects_ == SECTORS_PER_PAGE)
        {
            overwriteCompletePageInOwLog();
        }
        else
        {
            syncWithWriteLimit();
            UINT16 invalidChunksToDecrement = 0;
            chooseNewBank_();
            while(remainingSects_)
            {
                invalidChunksToDecrement++;
                UINT32 nSectsToWrite = (((sectOffset_ % SECTORS_PER_CHUNK) + remainingSects_) < SECTORS_PER_CHUNK) ? remainingSects_ :
                                                                                                                     (SECTORS_PER_CHUNK - (sectOffset_ % SECTORS_PER_CHUNK));
                if(nSectsToWrite == SECTORS_PER_CHUNK)
                {
                    uart_print("Copy chunk "); uart_print_int( (sectOffset_ % SECTORS_PER_CHUNK) / SECTORS_PER_CHUNK); uart_print(" to OW_LOG_BUF\r\n");
                    overwriteCompleteChunkNew();
                    updateOwDramBufMetadata();
                    updateOwChunkPtr();
                }
                else
                {
                    UINT32 chunkIdx = sectOffset_ / SECTORS_PER_CHUNK;
                    chunk = read_dram_32(ChunksMapTable(lpn_, chunkIdx));
                    chunk = chunk & 0x7FFFFFFF;
                    overwritePartialChunkWhenOldChunkIsInExhaustedOWLog(nSectsToWrite, chunk);
                    updateOwDramBufMetadata();
                    updateOwChunkPtr();
                }
                sectOffset_ += nSectsToWrite;
                remainingSects_ -= nSectsToWrite;
            }
            decrementValidChunksByN(&heapDataOverwrite, bank, lbn, invalidChunksToDecrement);
            g_ftl_write_buf_id = (g_ftl_write_buf_id + 1) % NUM_WR_BUFFERS;
            SETREG (BM_STACK_WRSET, g_ftl_write_buf_id);
            SETREG (BM_STACK_RESET, 0x01);
        }
    }
    #if MeasureDetailedOverwrite
    UINT32 timerValue=GET_TIMER_VALUE(TIMER_CH3);
    UINT32 nTicks = 0xFFFFFFFF - timerValue;
    uart_print_level_2("OPIO "); uart_print_level_2_int(nTicks); uart_print_level_2("\r\n");
    #endif
}
Esempio n. 18
0
static void overwritePartialPageOldNotInOrder()
{
    //uart_print_level_1("19 ");
    uart_print("overwritePartialPageOldNotInOrder\r\n");
    while (remainingSects_ != 0)
    {
        UINT32 chunkIdx = sectOffset_ / SECTORS_PER_CHUNK;
        //UINT32 chunkAddr = getChunkAddr(node_, chunkIdx);
        UINT32 chunkAddr = read_dram_32(ChunksMapTable(lpn_, chunkIdx));
        #if MeasureDetailedOverwrite
        start_interval_measurement(TIMER_CH3, TIMER_PRESCALE_0);
        #endif
        switch (findChunkLocation(chunkAddr))
        {
            case Invalid:
            {
                uart_print(" invalid\r\n");
                overwriteChunkNew();
                break;
            }
            case FlashWLog:
            {
                uart_print(" in w log\r\n");
                overwriteChunkOldInWLog(chunkAddr);
                #if MeasureDetailedOverwrite
                UINT32 timerValue=GET_TIMER_VALUE(TIMER_CH3);
                UINT32 nTicks = 0xFFFFFFFF - timerValue;
                uart_print_level_2("OCO3 "); uart_print_level_2_int(nTicks); uart_print_level_2("\r\n");
                #endif
                break;
            }
            case DRAMWLog:
            {
                uart_print(" in w DRAM buf\r\n");
                overwriteChunkOldInWBuf(chunkAddr);
                #if MeasureDetailedOverwrite
                UINT32 timerValue=GET_TIMER_VALUE(TIMER_CH3);
                UINT32 nTicks = 0xFFFFFFFF - timerValue;
                uart_print_level_2("OCO2 "); uart_print_level_2_int(nTicks); uart_print_level_2("\r\n");
                #endif
                break;
            }
            case DRAMOwLog:
            {
                uart_print(" in ow DRAM buf\r\n");
                chunkAddr = chunkAddr & 0x7FFFFFFF;
                overwriteChunkOldInOwBuf(chunkAddr);
                #if MeasureDetailedOverwrite
                UINT32 timerValue=GET_TIMER_VALUE(TIMER_CH3);
                UINT32 nTicks = 0xFFFFFFFF - timerValue;
                uart_print_level_2("OCO0 "); uart_print_level_2_int(nTicks); uart_print_level_2("\r\n");
                #endif
                break;
            }
            case FlashOwLog:
            {
                uart_print(" in ow log\r\n");
                chunkAddr = chunkAddr & 0x7FFFFFFF;
                overwriteChunkOldInOwLog(chunkAddr);
                #if MeasureDetailedOverwrite
                UINT32 timerValue=GET_TIMER_VALUE(TIMER_CH3);
                UINT32 nTicks = 0xFFFFFFFF - timerValue;
                uart_print_level_2("OCO1 "); uart_print_level_2_int(nTicks); uart_print_level_2("\r\n");
                #endif
                break;
            }
        }
    }
    // SATA buffer management
    g_ftl_write_buf_id = (g_ftl_write_buf_id + 1) % NUM_WR_BUFFERS;
    SETREG (BM_STACK_WRSET, g_ftl_write_buf_id);
    SETREG (BM_STACK_RESET, 0x01);
}
Esempio n. 19
0
// get vpn from PAGE_MAP
static UINT32 get_vpn(UINT32 const lpn)
{
    CHECK_LPAGE(lpn);
    return read_dram_32(PAGE_MAP_ADDR + lpn * sizeof(UINT32));
}
Esempio n. 20
0
// This function rebuilds a page into the FTL BUF. If one of the chunks is in the log buffer, returns 1, otherwise returns 0.
// If there's at least a chunk in log buffer, the page cannot be copied to data block, otherwise the lpn remains in the log buffer and will be reinserted when the log is flushed to flash.
void rebuildPageToFtlBuf(const UINT32 dataLpn, const UINT32 sectOffset, const UINT32 nSects, const UINT8 mode) {
    uart_print("rebuild page to FTL BUF lpn="); uart_print_int(dataLpn); uart_print("\r\n");
    initRead(dataLpn, sectOffset, nSects, mode);
    for (chunkIdx_ = sectOffset_ / SECTORS_PER_CHUNK; chunkIdx_<lastChunk_; chunkIdx_++) {
        uart_print("c "); uart_print_int(chunkIdx_); uart_print("\r\n");
        if (chunksDone_[chunkIdx_] == 0)
        {
            chunksDone_[chunkIdx_] = 1;
            //oldChunkAddr_ = getChunkAddr(node_, chunkIdx_);
            if (ChunksMapTable(dataLpn, chunkIdx_) > DRAM_BASE + DRAM_SIZE)
            {
                uart_print_level_1("ERROR in rebuildPageToFtlBuf 1: reading above DRAM address space\r\n");
            }
            oldChunkAddr_ = read_dram_32(ChunksMapTable(dataLpn, chunkIdx_));
            uart_print("oldChunkAddr is "); uart_print_int(oldChunkAddr_); uart_print("\r\n");
            switch (findChunkLocation(oldChunkAddr_))
            {
                case Invalid:
                {
                    uart_print(" not valid\r\n");
                    chunkInvalid();
                    continue;
                    break;
                }
                case FlashWLog:
                {
                    uart_print(" in flash w log\r\n");
                    chunkInFlashLog(FALSE);
                    continue;
                    break;
                }
                case DRAMWLog:
                {
                    uart_print(" in dram w log\r\n");
                    chunkInWDramBuf();
                    continue;
                    break;
                }
#if Overwrite
                case DRAMOwLog:
                {
                    uart_print(" in dram ow log\r\n");
                    oldChunkAddr_ = oldChunkAddr_ & 0x7FFFFFFF;
                    chunkInOWDramBuf();
                    break;
                }
                case FlashOwLog:
                {
                    uart_print(" in flash ow log\r\n");
                    oldChunkAddr_ = oldChunkAddr_ & 0x7FFFFFFF;
                    chunkInFlashLog(TRUE);
                    break;
                }
#endif
            }
        }
        else
        {
            uart_print(" already done\r\n");
        }
    }
}
void writePage(UINT32 bank)
{
    uart_print("writePage: bank="); uart_print_int(bank);
    uart_print(" victimLbn "); uart_print_int(victimLbn[bank]);
    uart_print(" pageOffset "); uart_print_int(pageOffset[bank]); uart_print(" ");

    if(nValidChunksInPage[bank] == 8)
    {

        UINT32 logChunkBase = ((bank*LOG_BLK_PER_BANK*CHUNKS_PER_BLK) + (victimLbn[bank]*CHUNKS_PER_BLK) + (pageOffset[bank]*CHUNKS_PER_PAGE));
        if (gcOnRecycledPage[bank])
        {
            logChunkBase = logChunkBase | ColdLogBufBitFlag;
        }

        for(UINT32 chunkOffset=0; chunkOffset<CHUNKS_PER_PAGE; chunkOffset++)
        {
            UINT32 chunkAddr = read_dram_32(ChunksMapTable(dataLpns[bank][chunkOffset], dataChunkOffsets[bank][chunkOffset]));

            // note (fabio): here we check against the normal chunkAddr (not recycled) because if there are 8 valid chunks the blk cannot be a recycled one
            if(chunkAddr != logChunkBase + chunkOffset)
            {
                // note(fabio): here invalidate only the first chunk that was moved by another write. If other chunks were also moved they'll be found by the code after the goto
                validChunks[bank][chunkOffset]=FALSE;
                nValidChunksInPage[bank]--;
                nValidChunksInBlk[bank]--;
                goto WritePartialPage;
            }

        }

        UINT32 dstLpn = getRWLpn(bank, coldLogCtrl);
        UINT32 dstVbn = get_log_vbn(bank, LogPageToLogBlk(dstLpn));
        UINT32 dstPageOffset = LogPageToOffset(dstLpn);

        uart_print(" dstLpn="); uart_print_int(dstLpn);
        uart_print(" dstVbn="); uart_print_int(dstVbn); uart_print(" dstPageOffset="); uart_print_int(dstPageOffset); uart_print("\r\n");

#if PrintStats
        uart_print_level_1("^\r\n");
#endif

        nand_page_program(bank, dstVbn, dstPageOffset, GC_BUF(bank), RETURN_ON_ISSUE);

        mem_copy(chunkInLpnsList(coldLogCtrl[bank].lpnsListAddr, dstPageOffset, 0), dataLpns[bank], CHUNKS_PER_PAGE * sizeof(UINT32));

        for (UINT32 chunkOffset=0; chunkOffset<CHUNKS_PER_PAGE; ++chunkOffset)
        {
            write_dram_32(ChunksMapTable(dataLpns[bank][chunkOffset], dataChunkOffsets[bank][chunkOffset]), (bank * LOG_BLK_PER_BANK * CHUNKS_PER_BLK) + (dstLpn * CHUNKS_PER_PAGE) + chunkOffset);
        }

        nValidChunksInPage[bank] = 0;
        gcOnRecycledPage[bank]=FALSE;

        gcState[bank] = GcRead;

        pageOffset[bank]++;

        coldLogCtrl[bank].increaseLpn(bank, coldLogCtrl);

    }
    else
WritePartialPage:
    {
        uart_print("write partial ");
        UINT32 chunkOffset=0;
        UINT32 logChunkBase=((bank*LOG_BLK_PER_BANK*CHUNKS_PER_BLK) + (victimLbn[bank]*CHUNKS_PER_BLK) + (pageOffset[bank]*CHUNKS_PER_PAGE));
        if (gcOnRecycledPage[bank])
        {
            logChunkBase = logChunkBase | ColdLogBufBitFlag;
            // note(fabio): Here we should decode
        }
        while(nValidChunksInPage[bank] > 0)
        {

            if(validChunks[bank][chunkOffset])
            {
                validChunks[bank][chunkOffset] = FALSE;
                nValidChunksInPage[bank]--;

                UINT32 chunkAddr = read_dram_32(ChunksMapTable(dataLpns[bank][chunkOffset], dataChunkOffsets[bank][chunkOffset]));

                if(chunkAddr == logChunkBase+chunkOffset)
                {

                    writeChunkOnLogBlockDuringGC(bank,
                                                 dataLpns[bank][chunkOffset],
                                                 dataChunkOffsets[bank][chunkOffset],
                                                 chunkOffset,
                                                 GC_BUF(bank));
                }
                else
                {
                    uart_print(" one chunk was moved during GC ");
                    nValidChunksInBlk[bank]--;
                }
            }
            chunkOffset++;
        }
        uart_print(" current nValidChunksInBlk="); uart_print_int(nValidChunksInBlk[bank]); uart_print("\r\n");

        if (gcState[bank] == GcWrite)
        {
            gcState[bank] = GcRead;
            gcOnRecycledPage[bank]=FALSE;
            pageOffset[bank]++;
        }
    }
}