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); }
static ssize_t ftl_write(FAR struct inode *inode, const unsigned char *buffer, size_t start_sector, unsigned int nsectors) { struct ftl_struct_s *dev; finfo("sector: %d nsectors: %d\n", start_sector, nsectors); DEBUGASSERT(inode && inode->i_private); dev = (struct ftl_struct_s *)inode->i_private; #ifdef CONFIG_FTL_WRITEBUFFER return rwb_write(&dev->rwb, start_sector, nsectors, buffer); #else return ftl_flush(dev, buffer, start_sector, nsectors); #endif }
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(); }
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(); }
void ata_flush_cache(UINT32 lba, UINT32 sector_count) { ftl_flush(); send_status_to_host(0); }
void ata_idle_immediate(UINT32 lba, UINT32 sector_count) { ftl_flush(); send_status_to_host(0); }