Exemple #1
0
static void format(void)
{
	// This function is called upon the very first power-up of the SSD.
	// This function does the low-level format (i.e. FTL level format) of SSD.
	// A typical FTL would create its mapping table and the list of free blocks.
	// However, this example does nothing more than erasing all the free blocks.
	//
	// This function may take a long time to complete. For example, erasing all the flash blocks can
	// take more than ten seconds depending on the total density.
	// In that case, the host will declare time-out error. (no response from SSD for a long time)
	// A suggested solution to this problem is:
	// When you power-up the SSD for the first time, connect the power cable but not the SATA cable.
	// At the end of this function, you can put a call to led(1) to indicate that the low level format
	// has been completed. When the LED is on, turn off the power, connect the SATA cable, and turn on
	// the power again.

	UINT32 vblk_offset, bank;

	for (vblk_offset = 1; vblk_offset < VBLKS_PER_BANK; vblk_offset++)
	{
		for (bank = 0; bank < NUM_BANKS; bank++)
		{
			if (is_bad_block(bank, vblk_offset))
				continue;

			// You do not need to set the values of FCP_DMA_ADDR, FCP_DMA_CNT and FCP_COL for FC_ERASE.

			SETREG(FCP_CMD, FC_ERASE);
			SETREG(FCP_BANK, REAL_BANK(bank));
			SETREG(FCP_OPTION, FO_P);
			SETREG(FCP_ROW_L(bank), vblk_offset * PAGES_PER_VBLK);
			SETREG(FCP_ROW_H(bank), vblk_offset * PAGES_PER_VBLK);

			// You should not issue a new command when Waiting Room is not empty.

			while ((GETREG(WR_STAT) & 0x00000001) != 0);

			// By writing any value to FCP_ISSUE, you put FC_ERASE into Waiting Room.
			// The value written to FCP_ISSUE does not have any meaning.

			SETREG(FCP_ISSUE, NULL);
		}
	}

	// In general, write_format_mark() should be called upon completion of low level format in order to prevent
	// format() from being called again.
	// However, since the tutorial FTL does not support power off recovery,
	// format() should be called every time.
	
	init_meta_data();
	ftl_flush();
	write_format_mark();
	led(1);
}
/**
 * @brief synchronized create_shard/write/read/delete/delete_shard operations
 */
void
user_operations_rms_sm_fault_in(uint64_t args) {
    struct replication_test_framework *test_framework =
        (struct replication_test_framework *)args;
    SDF_shardid_t shard_id = 1;
    struct SDF_shard_meta *shard_meta = NULL;
    struct sdf_replication_shard_meta *r_shard_meta;
    /* configuration infomation about shard */
    SDF_replication_props_t *replication_props = NULL;
    struct cr_shard_meta *in;
    vnode_t node = 0;
    int failed;
#if 0
    struct cr_shard_meta *out = NULL;
    SDF_status_t status = SDF_SUCCESS;
    struct timeval expires;
    struct timeval now;
#endif

    /* configures test framework accommodate to RT_TYPE_META_STORAGE */
    failed = !(plat_calloc_struct(&replication_props));
    plat_assert(!failed);

    rtfw_set_default_replication_props(&test_framework->config,
                                       replication_props);

    init_meta_data(test_framework, replication_props, &r_shard_meta, node, shard_id,
                   LEASE_USECS, &shard_meta, &in);

    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "start test_framework");
    rtfw_start(test_framework);
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "test_framework started\n");

    failed = rms_modify_shard_meta_fault_in(test_framework, replication_props);
    plat_assert(failed != 1);

    cr_shard_meta_free(in);
    plat_free(replication_props);

    /* Shutdown test framework */
    plat_log_msg(LOG_ID, LOG_CAT, LOG_TRACE,
                 "\n************************************************************\n"
                 "                  Test framework shutdown                       "
                 "\n************************************************************");
    rtfw_shutdown_sync(test_framework);

    /* Terminate scheduler */
    fthKill(1);
}
Exemple #3
0
void ftl_por_test()
{
	init_meta_data();
	loading_misc_meta();
}
Exemple #4
0
void ftl_open(void)
{
	sanity_check();

	// STEP 1 - read scan lists from NAND flash

	scan_list_t* scan_list = (scan_list_t*) SCAN_LIST_ADDR;
	UINT32 bank;
	UINT32 bad_block, i , j ;
	// Since we are going to check the flash interrupt flags within this function, ftl_isr() should not be called.
	disable_irq();

	flash_clear_irq();	// clear any flash interrupt flags that might have been set
	
	for (bank = 0; bank < NUM_BANKS; bank++)
	{
		//g_misc_meta[bank].g_merge_buff_sect = 0;
		SETREG(FCP_CMD, FC_COL_ROW_READ_OUT);			// FC_COL_ROW_READ_OUT = sensing and data output
		SETREG(FCP_OPTION, FO_E);						// scan list was written in 1-plane mode by install.exe, so there is no FO_P
		SETREG(FCP_DMA_ADDR, scan_list + bank);			// target address should be DRAM or SRAM (see flash.h for rules)
		SETREG(FCP_DMA_CNT, SCAN_LIST_SIZE);			// number of bytes for data output
		SETREG(FCP_COL, 0);
		SETREG(FCP_ROW_L(bank), SCAN_LIST_PAGE_OFFSET);	// scan list was written to this position by install.exe
		SETREG(FCP_ROW_H(bank), SCAN_LIST_PAGE_OFFSET);	// Tutorial FTL always uses the same row addresses for high chip and low chip

		flash_issue_cmd(bank, RETURN_ON_ISSUE);			// Take a look at the source code of flash_issue_cmd() now.
	}

	// This while() statement waits the last issued command to be accepted.
	// If bit #0 of WR_STAT is one, a flash command is in the Waiting Room, because the target bank has not accepted it yet.
	while ((GETREG(WR_STAT) & 0x00000001) != 0);

	// Now, FC_COL_ROW_READ_OUT commands are accepted by all the banks.
	// Before checking whether scan lists are corrupted or not, we have to wait the completion of read operations.
	// This code shows how to wait for ALL the banks to become idle.
	while (GETREG(MON_CHABANKIDLE) != 0);

	// Now we can check the flash interrupt flags.

	for (bank = 0; bank < NUM_BANKS; bank++)
	{
		UINT32 num_entries = NULL;
		UINT32 result = OK;

		if (BSP_INTR(bank) & FIRQ_DATA_CORRUPT)
		{
			// Too many bits are corrupted so that they cannot be corrected by ECC.
			result = FAIL;
		}
		else
		{
			// Even though the scan list is not corrupt, we have to check whether its contents make sense.

			UINT32 i;

			num_entries = read_dram_16(&(scan_list[bank].num_entries));

			if (num_entries > SCAN_LIST_ITEMS)
			{
				result = FAIL;	// We cannot trust this scan list. Perhaps a software bug.
			}
			else
			{
				for (i = 0; i < num_entries; i++)
				{
					UINT16 entry = read_dram_16(&(scan_list[bank].list[i]));
					UINT16 pblk_offset = entry & 0x7FFF;

					if (pblk_offset == 0 || pblk_offset >= PBLKS_PER_BANK)
					{
						#if OPTION_REDUCED_CAPACITY == FALSE
						result = FAIL;	// We cannot trust this scan list. Perhaps a software bug.
						#endif
					}
					else
					{
						// Bit position 15 of scan list entry is high-chip/low-chip flag.
						// Remove the flag in order to make is_bad_block() simple.

						write_dram_16(&(scan_list[bank].list[i]), pblk_offset);
					}
				}
			}
		}

		if (result == FAIL)
		{
			mem_set_dram(scan_list + bank, 0, SCAN_LIST_SIZE);
			g_misc_meta[bank].g_scan_list_entries = 0;
		}
		else
		{
			write_dram_16(&(scan_list[bank].num_entries), 0);
			g_misc_meta[bank].g_scan_list_entries = num_entries;
		}
	}

	// STEP 2 - If necessary, do low-level format
	// format() should be called after loading scan lists, because format() calls is_bad_block().
	init_meta_data();

	// save non bad block list for metadata block
	// block#0 : list, block#1 : misc meta
	// block#2 ~ map table meta and data
	for(i = 0 ;i < NUM_BANKS;i++){
		bad_block = 2;
		for(j = 0 ;j < NUM_BANKS_MAX;j++){
			while(is_bad_block(i, bad_block) && j < VBLKS_PER_BANK)
			{
				bad_block++;
			}
			g_bad_list[i][j] = bad_block++;
		}
		g_free_start[i] = g_bad_list[i][NUM_BANKS_MAX-1] + 1;
	}
	//if (check_format_mark() == FALSE)
	if( TRUE)
	{
		// When ftl_open() is called for the first time (i.e. the SSD is powered up the first time)
		// format() is called.

		format();
	}
	else{
		loading_misc_meta();
	}


	//*Red//
	// STEP 3 - initialize sector mapping table pieces
	// The page mapping table is too large to fit in SRAM and DRAM.
	// gyuhwa
//	init_metadata();
	// STEP 4 - initialize global variables that belong to FTL

	g_ftl_read_buf_id = 0;
	g_ftl_write_buf_id = 0;

	for (bank = 0; bank < NUM_BANKS; bank++)
	{
		g_misc_meta[bank].g_target_row = PAGES_PER_VBLK * (g_free_start[bank]);
	}

	flash_clear_irq();

	// This example FTL can handle runtime bad block interrupts and read fail (uncorrectable bit errors) interrupts

	SETREG(INTR_MASK, FIRQ_DATA_CORRUPT | FIRQ_BADBLK_L | FIRQ_BADBLK_H);
	SETREG(FCONF_PAUSE, FIRQ_DATA_CORRUPT | FIRQ_BADBLK_L | FIRQ_BADBLK_H);

	enable_irq();
}
static int
rms_modify_shard_meta_fault_in(struct replication_test_framework *test_framework,
                               SDF_replication_props_t *replication_props) {
    SDF_status_t status;
    struct SDF_shard_meta *shard_meta;
    struct sdf_replication_shard_meta *r_shard_meta;
    SDF_shardid_t shard_id = 1;
    vnode_t node = 1;
    struct cr_shard_meta *in;
    struct cr_shard_meta *out;
    struct cr_shard_meta *temp;
    struct timeval expires;

    /* init cr_shard_meta and shard_meta */
    init_meta_data(test_framework, replication_props, &r_shard_meta, node, shard_id,
                   LEASE_USECS, &shard_meta, &in);
    plat_assert(r_shard_meta);
    plat_assert(shard_meta);
    plat_assert(in);

    /* put meta on node 1 */
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "create on node 1");
    status = rtfw_create_shard_meta_sync(test_framework, node, in, &out,
                                         &expires);
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "create on node 1 complete");
    /* perhaps shard has been created in other unit test since currently we can't delete shard meta */
    plat_assert(status == SDF_SUCCESS || status == SDF_FAILURE_STORAGE_WRITE);
    if (status == SDF_SUCCESS) {
        plat_assert(out);
        hs_print_current_lease(in);
        hs_print_current_lease(out);

        out->persistent.lease_usecs = in->persistent.lease_usecs;
        plat_assert(0 == cr_shard_meta_cmp(in, out));
        cr_shard_meta_free(out);
    }

    /* get meta on node0 */
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "get on node 0");
    status = rtfw_get_shard_meta_sync(test_framework, node,
                                      in->persistent.sguid, r_shard_meta, &out,
                                      &expires);
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "get on node 0 complete");
    plat_assert(status == SDF_SUCCESS);
    plat_assert(out);
    hs_print_current_lease(in);
    hs_print_current_lease(out);

    /* buffer an cr_shard_meta here */
    temp = cr_shard_meta_dup(out);
    plat_assert(temp);

    out->persistent.lease_usecs = in->persistent.lease_usecs;
    plat_assert(0 == cr_shard_meta_cmp(in, out));
    cr_shard_meta_free(out);

    /* modify meta data before expire */
    /* fault injections */
    /* (1) put meta data with incorrect ltime non home node */
    in->persistent.ltime = -1;
    ++in->persistent.shard_meta_seqno;
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "put shard meta on node 1 with illegal ltime");
    status = rtfw_put_shard_meta_sync(test_framework, 1, in, &out,
                                      &expires);
    plat_assert(status == SDF_SUCCESS);
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "put shard meta on node 1 with illegal ltime complete");
    /**
     * Fixme: zhenwei, shard meta with incorrect ltime can be set to any node
     */
    temp->persistent.lease_usecs = out->persistent.lease_usecs;
    plat_assert(0 != cr_shard_meta_cmp(temp, out));

    /* buffer the latest cr_shard_meta */
    cr_shard_meta_free(temp);
    temp = cr_shard_meta_dup(out);
    cr_shard_meta_free(out);

    /* (2) put meta data with incorrect seqno */
    in->persistent.shard_meta_seqno += 2;
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "put shard meta on node 1 with illegal ltime");
    status = rtfw_put_shard_meta_sync(test_framework, 1, in, &out,
                                      &expires);
    plat_assert(status != SDF_SUCCESS);
    status = SDF_SUCCESS;
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "put shard meta on node 1 with illegal ltime complete");
    plat_assert(temp->persistent.ltime == out->persistent.ltime &&
                temp->persistent.shard_meta_seqno == out->persistent.shard_meta_seqno);
                
    /* buffer the latest cr_shard_meta */
    cr_shard_meta_free(temp);
    temp = cr_shard_meta_dup(out);
    cr_shard_meta_free(out);

    /* (3) put meta data with a lease than LEASE_USECS */
    in->persistent.lease_usecs = LEASE_USECS * 2;
    /* skip since (2) +2 for it */
    /* ++in->persistent.shard_meta_seqno; */
    --in->persistent.shard_meta_seqno;
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "put shard meta on node 1 with illegal ltime");
    status = rtfw_put_shard_meta_sync(test_framework, 1, in, &out,
                                      &expires);
    plat_assert(status == SDF_SUCCESS);
    out->persistent.lease_usecs = in->persistent.lease_usecs;
    plat_assert(0 == cr_shard_meta_cmp(in, out));

    cr_shard_meta_free(out);
    cr_shard_meta_free(temp);
    cr_shard_meta_free(in);


    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "put shard meta on node 1 with illegal ltime");

    plat_free(shard_meta);
    plat_free(r_shard_meta);

    return (status == SDF_SUCCESS ? 0 : 1);
}
static int
hs_expire_simple(struct replication_test_framework *test_framework,
                 SDF_replication_props_t *replication_props) {
    SDF_status_t status;
    struct SDF_shard_meta *shard_meta;
    struct sdf_replication_shard_meta *r_shard_meta;
    SDF_shardid_t shard_id;
    vnode_t node = 0;
    struct cr_shard_meta *in;
    struct cr_shard_meta *out;
    struct timeval expires;

    /* init cr_shard_meta and shard_meta */
    init_meta_data(test_framework, replication_props, &r_shard_meta, node, shard_id,
                   LEASE_USECS, &shard_meta, &in);
    plat_assert(r_shard_meta);
    plat_assert(shard_meta);
    plat_assert(in);

    /* put meta on node 0 */
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "create on node 0");
    status = rtfw_create_shard_meta_sync(test_framework, node, in, &out,
                                         &expires);
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "create on node 0 complete");

    /* perhaps shard has been created in other unit test */
    plat_assert(status == SDF_SUCCESS || status == SDF_FAILURE_STORAGE_WRITE);
    if (status == SDF_SUCCESS) {
        plat_assert(out);
        hs_print_current_lease(in);
        hs_print_current_lease(out);

        out->persistent.lease_usecs = in->persistent.lease_usecs;
        plat_assert(0 == cr_shard_meta_cmp(in, out));
        cr_shard_meta_free(out);
    }

    /*
     * XXX: drew 2009-05-09 sleep and validate that less time remains on the
     * lease.
     */
    
    rtfw_sleep_usec(test_framework, 2000000);
    /* get meta on node0 */
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "get on node 0");
    status = rtfw_get_shard_meta_sync(test_framework, node,
                                      in->persistent.sguid, r_shard_meta, &out,
                                      &expires);
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "get on node 0 complete");
    plat_assert(status == SDF_SUCCESS);
    plat_assert(out);
    
    hs_print_current_lease(in);
    hs_print_current_lease(out);
    plat_assert(in->persistent.lease_usecs > out->persistent.lease_usecs);

    out->persistent.lease_usecs = in->persistent.lease_usecs;
    plat_assert(0 == cr_shard_meta_cmp(in, out));
    cr_shard_meta_free(out);

    /* verify get shard meta does not renew lease */
    rtfw_sleep_usec(test_framework, 2000000);
    /* get meta on node1 */
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "first get on node 1");
    status = rtfw_get_shard_meta_sync(test_framework, 1,
                                      in->persistent.sguid,
                                      r_shard_meta, &out, &expires);
    plat_log_msg(LOG_ID, LOG_CAT, LOG_DBG, "first get on node 1 complete");
    plat_assert(status == SDF_SUCCESS);
    plat_assert(out);
    
    hs_print_current_lease(in);
    hs_print_current_lease(out);

    out->persistent.lease_usecs = in->persistent.lease_usecs;
    plat_assert(0 == cr_shard_meta_cmp(in, out));
    cr_shard_meta_free(out);

    plat_free(shard_meta);
    plat_free(r_shard_meta);

    return ((status == SDF_SUCCESS)? 0 : 1);
}