diff --git a/hw/femu/zns/zftl.c b/hw/femu/zns/zftl.c index 9659db0e5e..cad6cd9569 100644 --- a/hw/femu/zns/zftl.c +++ b/hw/femu/zns/zftl.c @@ -54,16 +54,22 @@ static inline void check_addr(int a, int max) static void zns_advance_write_pointer(struct zns_ssd *zns) { struct write_pointer *wpp = &zns->wp; - - check_addr(wpp->ch, zns->num_ch); + //Misao: the ch-lun-pl pair iterates as "0-0-0","1-0-0","0-1-0","1-1-0","0-0-1","1-0-1",... + check_addr(wpp->ch, zns->num_chs); wpp->ch++; - if (wpp->ch == zns->num_ch) { + if (wpp->ch == zns->num_chs) { wpp->ch = 0; - check_addr(wpp->lun, zns->num_lun); + check_addr(wpp->lun, zns->luns_per_ch); wpp->lun++; - /* in this case, we should go to next lun */ - if (wpp->lun == zns->num_lun) { + if (wpp->lun == zns->luns_per_ch) { wpp->lun = 0; + check_addr(wpp->pl, zns->planes_per_lun); + wpp->pl++; + //Misao: new loop + if(wpp->pl == zns->planes_per_lun) + { + wpp->pl = 0; + } } } } @@ -125,8 +131,8 @@ static inline bool valid_ppa(struct zns_ssd *zns, struct ppa *ppa) int pg = ppa->g.pg; int sub_pg = ppa->g.spg; - if (ch >= 0 && ch < zns->num_ch && lun >= 0 && lun < zns->num_lun && pl >= - 0 && pl < zns->num_plane && blk >= 0 && blk < zns->num_blk && pg>=0 && pg < zns->num_page && sub_pg >= 0 && sub_pg < ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE) + if (ch >= 0 && ch < zns->num_chs && lun >= 0 && lun < zns->luns_per_ch && pl >= + 0 && pl < zns->planes_per_lun && blk >= 0 && blk < zns->blks_per_plane && pg>=0 && pg < zns->flashpages_per_blk && sub_pg >= 0 && sub_pg < zns->pages_per_flashpage) return true; return false; @@ -144,6 +150,7 @@ static struct ppa get_new_page(struct zns_ssd *zns) ppa.ppa = 0; ppa.g.ch = wpp->ch; ppa.g.fc = wpp->lun; + ppa.g.pl = wpp->pl; ppa.g.blk = zns->active_zone; ppa.g.V = 1; //not padding page if(!valid_ppa(zns,&ppa)) @@ -186,14 +193,17 @@ static uint64_t zns_read(struct zns_ssd *zns, NvmeRequest *req) continue; } - struct nand_cmd srd; - srd.type = USER_IO; - srd.cmd = NAND_READ; - srd.stime = req->stime; + if(lpn == end_lpn || lpn%zns->pages_per_flashpage == zns->pages_per_flashpage-1) + { + struct nand_cmd srd; + srd.type = USER_IO; + srd.cmd = NAND_READ; + srd.stime = req->stime; - sublat = zns_advance_status(zns, &ppa, &srd); - femu_log("[R] lpn:\t%lu\t<--ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat); - maxlat = (sublat > maxlat) ? sublat : maxlat; + sublat = zns_advance_status(zns, &ppa, &srd); + femu_log("[R] lpn:\t%lu\t<--ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat); + maxlat = (sublat > maxlat) ? sublat : maxlat; + } } return maxlat; @@ -201,7 +211,7 @@ static uint64_t zns_read(struct zns_ssd *zns, NvmeRequest *req) static uint64_t zns_wc_flush(struct zns_ssd* zns, int wcidx, int type,uint64_t stime) { - int i,j,p,subpage; + int i,j,subpage; struct ppa ppa; struct ppa oldppa; uint64_t lpn; @@ -211,44 +221,41 @@ static uint64_t zns_wc_flush(struct zns_ssd* zns, int wcidx, int type,uint64_t s i = 0; while(i < zns->cache.write_cache[wcidx].used) { - for(p = 0;pnum_plane;p++){ - /* new write */ - ppa = get_new_page(zns); - ppa.g.pl = p; - for(j = 0; j < flash_type ;j++) + /* new write */ + ppa = get_new_page(zns); + for(j = 0; j < flash_type ;j++) + { + ppa.g.pg = get_blk(zns,&ppa)->page_wp; + get_blk(zns,&ppa)->page_wp++; + for(subpage = 0;subpage < ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;subpage++) { - ppa.g.pg = get_blk(zns,&ppa)->page_wp; - get_blk(zns,&ppa)->page_wp++; - for(subpage = 0;subpage < ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;subpage++) + if(i+subpage >= zns->cache.write_cache[wcidx].used) { - if(i+subpage >= zns->cache.write_cache[wcidx].used) - { - //No need to write an invalid page - break; - } - lpn = zns->cache.write_cache[wcidx].lpns[i+subpage]; - oldppa = get_maptbl_ent(zns, lpn); - if (mapped_ppa(&oldppa)) { - /* FIXME: Misao: update old page information*/ - } - ppa.g.spg = subpage; - /* update maptbl */ - set_maptbl_ent(zns, lpn, &ppa); - //femu_log("[F] lpn:\t%lu\t-->ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat); + break; } - i+=ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE; - } - //FIXME Misao: identify padding page - if(ppa.g.V) - { - struct nand_cmd swr; - swr.type = type; - swr.cmd = NAND_WRITE; - swr.stime = stime; - /* get latency statistics */ - sublat = zns_advance_status(zns, &ppa, &swr); - maxlat = (sublat > maxlat) ? sublat : maxlat; + lpn = zns->cache.write_cache[wcidx].lpns[i+subpage]; + oldppa = get_maptbl_ent(zns, lpn); + if (mapped_ppa(&oldppa)) { + femu_err("%s: in-place update in zns??\n",__func__); + assert(0); + } + ppa.g.spg = subpage; + /* update maptbl */ + set_maptbl_ent(zns, lpn, &ppa); + //femu_log("[F] lpn:\t%lu\t-->ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat); } + i+=ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE; + } + //FIXME Misao: identify padding page + if(ppa.g.V) + { + struct nand_cmd swr; + swr.type = type; + swr.cmd = NAND_WRITE; + swr.stime = stime; + /* get latency statistics */ + sublat = zns_advance_status(zns, &ppa, &swr); + maxlat = (sublat > maxlat) ? sublat : maxlat; } /* need to advance the write pointer here */ zns_advance_write_pointer(zns); @@ -271,7 +278,7 @@ static uint64_t zns_write(struct zns_ssd *zns, NvmeRequest *req) if(wcidx==-1) { - //need flush + //Misao: Select the empty write cache or the write cache that aggregated the most valid data to flush wcidx = 0; uint64_t t_used = zns->cache.write_cache[wcidx].used; for(i = 1;i < zns->cache.num_wc;i++) @@ -309,6 +316,32 @@ static uint64_t zns_write(struct zns_ssd *zns, NvmeRequest *req) return maxlat; } +void zns_reset(struct zns_ssd *zns, uint32_t zid, uint64_t slba, uint64_t elba) +{ + int lpn; + struct ppa ppa; + struct zns_blk *blk; + uint64_t secs_per_pg = LOGICAL_PAGE_SIZE/zns->lbasz; + uint64_t slpn = slba / secs_per_pg; + uint64_t elpn = elba / secs_per_pg; + + for(lpn = slpn; lpn <= elpn; lpn++){ + ppa = get_maptbl_ent(zns,lpn); + blk = get_blk(zns,&ppa); + blk->ipc++; + if(blk->ipc == zns->pages_per_flashpage*zns->flashpages_per_blk) + { + struct nand_cmd erase; + erase.cmd = NAND_ERASE; + erase.stime = 0; + zns_advance_status(zns,&ppa,&erase); + blk->ipc = 0; + } + ppa.ppa = UNMAPPED_PPA; + set_maptbl_ent(zns,lpn,&ppa); + } +} + static void *ftl_thread(void *arg) { FemuCtrl *n = (FemuCtrl *)arg; diff --git a/hw/femu/zns/zftl.h b/hw/femu/zns/zftl.h index f7521ba3df..2f8528231b 100644 --- a/hw/femu/zns/zftl.h +++ b/hw/femu/zns/zftl.h @@ -8,6 +8,7 @@ #define UNMAPPED_PPA (~(0ULL)) void zftl_init(FemuCtrl *n); +void zns_reset(struct zns_ssd *zns, uint32_t zid, uint64_t slba, uint64_t elba); #ifdef FEMU_DEBUG_ZFTL #define ftl_debug(fmt, ...) \ diff --git a/hw/femu/zns/zns.c b/hw/femu/zns/zns.c index 3b893975a3..2b2d057aef 100644 --- a/hw/femu/zns/zns.c +++ b/hw/femu/zns/zns.c @@ -54,6 +54,7 @@ static int zns_init_zone_geometry(NvmeNamespace *ns, Error **errp) n->zone_size = zone_size / lbasz; n->zone_capacity = zone_cap / lbasz; n->num_zones = ns->size / lbasz / n->zone_size; + femu_log("zone size(# of sectors): %ld, zone capacity %ld, num zons %d\n",n->zone_size,n->zone_capacity,n->num_zones); if (n->max_open_zones > n->num_zones) { femu_err("max_open_zones value %u exceeds the number of zones %u", @@ -524,23 +525,7 @@ static void zns_aio_zone_reset_cb(NvmeRequest *req, NvmeZone *zone) break; } -#if 0 - FemuCtrl *n = ns->ctrl; - int ch, lun; - struct zns_ssd *zns = n->zns; - uint64_t num_ch = zns->num_ch; - uint64_t num_lun = zns->num_lun; - - struct ppa ppa; - for (ch = 0; ch < num_ch; ch++) { - for (lun = 0; lun < num_lun; lun++) { - ppa.g.ch = ch; - ppa.g.fc = lun; - ppa.g.blk = zns_zone_idx(ns, zone->d.zslba); - //FIXME: no erase - } - } -#endif + zns_reset(ns->ctrl->zns, zns_zone_idx(ns, zone->d.zslba), zone->d.zslba, zns_zone_rd_boundary(ns,zone)); } typedef uint16_t (*op_handler_t)(NvmeNamespace *, NvmeZone *, NvmeZoneState, @@ -1244,17 +1229,18 @@ static void zns_init_params(FemuCtrl *n) int i; id_zns = g_malloc0(sizeof(struct zns_ssd)); - id_zns->num_ch = n->zns_params.zns_num_ch; - id_zns->num_lun = n->zns_params.zns_num_lun; - id_zns->num_plane = n->zns_params.zns_num_plane; - id_zns->num_blk = n->zns_params.zns_num_blk; - id_zns->num_page = n->ns_size/ZNS_PAGE_SIZE/(id_zns->num_ch*id_zns->num_lun*id_zns->num_blk); + id_zns->num_chs = n->zns_params.zns_num_ch; + id_zns->luns_per_ch = n->zns_params.zns_num_lun; + id_zns->planes_per_lun = n->zns_params.zns_num_plane; + id_zns->blks_per_plane = n->zns_params.zns_num_blk; + id_zns->flashpages_per_blk = n->ns_size/ZNS_PAGE_SIZE/(id_zns->num_chs*id_zns->luns_per_ch*id_zns->planes_per_lun*id_zns->blks_per_plane); + id_zns->pages_per_flashpage = ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE; id_zns->lbasz = 1 << zns_ns_lbads(&n->namespaces[0]); id_zns->flash_type = n->zns_params.zns_flash_type; - id_zns->ch = g_malloc0(sizeof(struct zns_ch) * id_zns->num_ch); - for (i =0; i < id_zns->num_ch; i++) { - zns_init_ch(&id_zns->ch[i], id_zns->num_lun,id_zns->num_plane,id_zns->num_blk,id_zns->flash_type); + id_zns->ch = g_malloc0(sizeof(struct zns_ch) * id_zns->num_chs); + for (i =0; i < id_zns->num_chs; i++) { + zns_init_ch(&id_zns->ch[i], id_zns->luns_per_ch,id_zns->planes_per_lun,id_zns->blks_per_plane,id_zns->flash_type); } id_zns->wp.ch = 0; @@ -1267,9 +1253,9 @@ static void zns_init_params(FemuCtrl *n) id_zns->maptbl[i].ppa = UNMAPPED_PPA; } - //Misao: init sram - id_zns->program_unit = ZNS_PAGE_SIZE*id_zns->flash_type*2; //PAGE_SIZE*flash_type*2 planes - id_zns->stripe_uint = id_zns->program_unit*id_zns->num_ch*id_zns->num_lun; + //Misao: init buffer + id_zns->program_unit = ZNS_PAGE_SIZE*id_zns->flash_type*id_zns->planes_per_lun; + id_zns->stripe_uint = id_zns->program_unit*id_zns->num_chs*id_zns->luns_per_ch; id_zns->cache.num_wc = ZNS_DEFAULT_NUM_WRITE_CACHE; id_zns->cache.write_cache = g_malloc0(sizeof(struct zns_write_cache) * id_zns->cache.num_wc); for(i =0; i < id_zns->cache.num_wc; i++) @@ -1281,19 +1267,17 @@ static void zns_init_params(FemuCtrl *n) } femu_log("===========================================\n"); - femu_log("| ZMS HW Configuration() |\n"); + femu_log("| ZNS HW Configuration() |\n"); femu_log("===========================================\n"); - femu_log("|\tnchnl\t: %lu\t|\tchips per chnl\t: %lu\t|\tplanes per chip\t: %lu\t|\tblks per plane\t: %lu\t|\tpages per blk\t: %lu\t|\n",id_zns->num_ch,id_zns->num_lun,id_zns->num_plane,id_zns->num_blk,id_zns->num_page); + femu_log("|\tnchnl\t: %lu\t|\tchips per chnl\t: %lu\t|\tplanes per chip\t: %lu\t|\tblks per plane\t: %lu\t|\tflashpages per blk\t: %lu\t|\n",id_zns->num_chs,id_zns->luns_per_ch,id_zns->planes_per_lun,id_zns->blks_per_plane,id_zns->flashpages_per_blk); //femu_log("|\tl2p sz\t: %lu\t|\tl2p cache sz\t: %u\t|\n",id_zns->l2p_sz,id_zns->cache.num_l2p_ent); femu_log("|\tprogram unit\t: %lu KiB\t|\tstripe unit\t: %lu KiB\t|\t# of write caches\t: %u\t|\t size of write caches (4KiB)\t: %lu\t|\n",id_zns->program_unit/(KiB),id_zns->stripe_uint/(KiB),id_zns->cache.num_wc,(id_zns->stripe_uint/LOGICAL_PAGE_SIZE)); femu_log("===========================================\n"); - //Misao: use average read latency id_zns->timing.pg_rd_lat[SLC] = SLC_READ_LATENCY_NS; id_zns->timing.pg_rd_lat[TLC] = TLC_READ_LATENCY_NS; id_zns->timing.pg_rd_lat[QLC] = QLC_READ_LATENCY_NS; - //Misao: do not suppirt partial programing id_zns->timing.pg_wr_lat[SLC] = SLC_PROGRAM_LATENCY_NS; id_zns->timing.pg_wr_lat[TLC] = TLC_PROGRAM_LATENCY_NS; id_zns->timing.pg_wr_lat[QLC] = QLC_PROGRAM_LATENCY_NS; @@ -1307,7 +1291,6 @@ static void zns_init_params(FemuCtrl *n) n->zns = id_zns; - //Misao: init ftl zftl_init(n); } @@ -1317,7 +1300,8 @@ static int zns_init_zone_cap(FemuCtrl *n) struct zns_ssd* zns = n->zns; n->zoned = true; n->zasl_bs = NVME_DEFAULT_MAX_AZ_SIZE; - n->zone_size_bs = zns->num_ch*zns->num_lun*zns->num_plane*zns->num_page*ZNS_PAGE_SIZE; + //Misao: we always assume that a zone is the same size as a superblock. + n->zone_size_bs = zns->num_chs*zns->luns_per_ch*zns->planes_per_lun*zns->flashpages_per_blk*ZNS_PAGE_SIZE; n->zone_cap_bs = 0; n->cross_zone_read = false; n->max_active_zones = 0; @@ -1329,6 +1313,7 @@ static int zns_init_zone_cap(FemuCtrl *n) static int zns_start_ctrl(FemuCtrl *n) { + femu_debug("%s, n->page_size = %d\n",__func__,n->page_size); /* Coperd: let's fail early before anything crazy happens */ assert(n->page_size == 4096); diff --git a/hw/femu/zns/zns.h b/hw/femu/zns/zns.h index 2895d9802a..a5050502fb 100644 --- a/hw/femu/zns/zns.h +++ b/hw/femu/zns/zns.h @@ -84,6 +84,7 @@ struct ppa { struct write_pointer { uint64_t ch; uint64_t lun; + uint64_t pl; }; struct nand_cmd { @@ -97,6 +98,7 @@ struct zns_blk { int nand_type; uint64_t next_blk_avail_time; uint64_t page_wp; //next free page + uint64_t ipc; //invalid page count }; struct zns_plane{ @@ -128,17 +130,18 @@ struct zns_write_cache{ uint64_t* lpns; //identify the cached data }; -struct zns_sram{ +struct zns_buffer{ int num_wc; struct zns_write_cache* write_cache; }; struct zns_ssd { - uint64_t num_ch; - uint64_t num_lun; - uint64_t num_plane; - uint64_t num_blk; - uint64_t num_page; + uint64_t num_chs; + uint64_t luns_per_ch; + uint64_t planes_per_lun; + uint64_t blks_per_plane; + uint64_t flashpages_per_blk; + uint64_t pages_per_flashpage; struct zns_ch *ch; struct write_pointer wp; @@ -147,7 +150,7 @@ struct zns_ssd { int flash_type; uint64_t program_unit; uint64_t stripe_uint; - struct zns_sram cache; + struct zns_buffer cache; /*Misao: we still need a ftl in consumer devices*/ uint64_t l2p_sz; /* = # of 4KiB pages*/