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); }
void ftl_por_test() { init_meta_data(); loading_misc_meta(); }
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); }