[PATCH 11/12] lightnvm: pblk: implement get log report chunk

2018-03-02 Thread Javier González
In preparation of pblk supporting 2.0, implement the get log report
chunk in pblk. Also, define the chunk states as given in the 2.0 spec.

Signed-off-by: Javier González 
---
 drivers/lightnvm/pblk-core.c | 138 +++
 drivers/lightnvm/pblk-init.c | 222 ++-
 drivers/lightnvm/pblk.h  |   7 ++
 include/linux/lightnvm.h |  13 +++
 4 files changed, 298 insertions(+), 82 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 2e10b18b61e3..da9ae331a0cd 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -44,11 +44,12 @@ static void pblk_line_mark_bb(struct work_struct *work)
 }
 
 static void pblk_mark_bb(struct pblk *pblk, struct pblk_line *line,
-struct ppa_addr *ppa)
+struct ppa_addr ppa_addr)
 {
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = >geo;
-   int pos = pblk_ppa_to_pos(geo, *ppa);
+   struct ppa_addr *ppa;
+   int pos = pblk_ppa_to_pos(geo, ppa_addr);
 
pr_debug("pblk: erase failed: line:%d, pos:%d\n", line->id, pos);
atomic_long_inc(>erase_failed);
@@ -58,26 +59,38 @@ static void pblk_mark_bb(struct pblk *pblk, struct 
pblk_line *line,
pr_err("pblk: attempted to erase bb: line:%d, pos:%d\n",
line->id, pos);
 
+   /* Not necessary to mark bad blocks on 2.0 spec. */
+   if (geo->version == NVM_OCSSD_SPEC_20)
+   return;
+
+   ppa = kmalloc(sizeof(struct ppa_addr), GFP_ATOMIC);
+   if (!ppa)
+   return;
+
+   *ppa = ppa_addr;
pblk_gen_run_ws(pblk, NULL, ppa, pblk_line_mark_bb,
GFP_ATOMIC, pblk->bb_wq);
 }
 
 static void __pblk_end_io_erase(struct pblk *pblk, struct nvm_rq *rqd)
 {
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   struct nvm_chk_meta *chunk;
struct pblk_line *line;
+   int pos;
 
line = >lines[pblk_ppa_to_line(rqd->ppa_addr)];
+   pos = pblk_ppa_to_pos(geo, rqd->ppa_addr);
+   chunk = >chks[pos];
+
atomic_dec(>left_seblks);
 
if (rqd->error) {
-   struct ppa_addr *ppa;
-
-   ppa = kmalloc(sizeof(struct ppa_addr), GFP_ATOMIC);
-   if (!ppa)
-   return;
-
-   *ppa = rqd->ppa_addr;
-   pblk_mark_bb(pblk, line, ppa);
+   chunk->state = NVM_CHK_ST_OFFLINE;
+   pblk_mark_bb(pblk, line, rqd->ppa_addr);
+   } else {
+   chunk->state = NVM_CHK_ST_FREE;
}
 
atomic_dec(>inflight_io);
@@ -92,6 +105,49 @@ static void pblk_end_io_erase(struct nvm_rq *rqd)
mempool_free(rqd, pblk->e_rq_pool);
 }
 
+/*
+ * Get information for all chunks from the device.
+ *
+ * The caller is responsible for freeing the returned structure
+ */
+struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk)
+{
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   struct nvm_chk_meta *meta;
+   struct ppa_addr ppa;
+   unsigned long len;
+   int ret;
+
+   ppa.ppa = 0;
+
+   len = geo->all_chunks * sizeof(*meta);
+   meta = kzalloc(len, GFP_KERNEL);
+   if (!meta)
+   return ERR_PTR(-ENOMEM);
+
+   ret = nvm_get_chunk_meta(dev, meta, ppa, geo->all_chunks);
+   if (ret) {
+   kfree(meta);
+   return ERR_PTR(-EIO);
+   }
+
+   return meta;
+}
+
+struct nvm_chk_meta *pblk_chunk_get_off(struct pblk *pblk,
+ struct nvm_chk_meta *meta,
+ struct ppa_addr ppa)
+{
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   int ch_off = ppa.m.grp * geo->num_chk * geo->num_lun;
+   int lun_off = ppa.m.pu * geo->num_chk;
+   int chk_off = ppa.m.chk;
+
+   return meta + ch_off + lun_off + chk_off;
+}
+
 void __pblk_map_invalidate(struct pblk *pblk, struct pblk_line *line,
   u64 paddr)
 {
@@ -1094,10 +1150,34 @@ static int pblk_line_init_bb(struct pblk *pblk, struct 
pblk_line *line,
return 1;
 }
 
+static int pblk_prepare_new_line(struct pblk *pblk, struct pblk_line *line)
+{
+   struct pblk_line_meta *lm = >lm;
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   int blk_to_erase = atomic_read(>blk_in_line);
+   int i;
+
+   for (i = 0; i < lm->blk_per_line; i++) {
+   struct pblk_lun *rlun = >luns[i];
+   int pos = pblk_ppa_to_pos(geo, rlun->bppa);
+   int state = line->chks[pos].state;
+
+   /* Free chunks should not be erased */
+   if (state & NVM_CHK_ST_FREE) {
+   

[PATCH 11/12] lightnvm: pblk: implement get log report chunk

2018-03-02 Thread Javier González
In preparation of pblk supporting 2.0, implement the get log report
chunk in pblk. Also, define the chunk states as given in the 2.0 spec.

Signed-off-by: Javier González 
---
 drivers/lightnvm/pblk-core.c | 138 +++
 drivers/lightnvm/pblk-init.c | 222 ++-
 drivers/lightnvm/pblk.h  |   7 ++
 include/linux/lightnvm.h |  13 +++
 4 files changed, 298 insertions(+), 82 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 2e10b18b61e3..da9ae331a0cd 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -44,11 +44,12 @@ static void pblk_line_mark_bb(struct work_struct *work)
 }
 
 static void pblk_mark_bb(struct pblk *pblk, struct pblk_line *line,
-struct ppa_addr *ppa)
+struct ppa_addr ppa_addr)
 {
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = >geo;
-   int pos = pblk_ppa_to_pos(geo, *ppa);
+   struct ppa_addr *ppa;
+   int pos = pblk_ppa_to_pos(geo, ppa_addr);
 
pr_debug("pblk: erase failed: line:%d, pos:%d\n", line->id, pos);
atomic_long_inc(>erase_failed);
@@ -58,26 +59,38 @@ static void pblk_mark_bb(struct pblk *pblk, struct 
pblk_line *line,
pr_err("pblk: attempted to erase bb: line:%d, pos:%d\n",
line->id, pos);
 
+   /* Not necessary to mark bad blocks on 2.0 spec. */
+   if (geo->version == NVM_OCSSD_SPEC_20)
+   return;
+
+   ppa = kmalloc(sizeof(struct ppa_addr), GFP_ATOMIC);
+   if (!ppa)
+   return;
+
+   *ppa = ppa_addr;
pblk_gen_run_ws(pblk, NULL, ppa, pblk_line_mark_bb,
GFP_ATOMIC, pblk->bb_wq);
 }
 
 static void __pblk_end_io_erase(struct pblk *pblk, struct nvm_rq *rqd)
 {
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   struct nvm_chk_meta *chunk;
struct pblk_line *line;
+   int pos;
 
line = >lines[pblk_ppa_to_line(rqd->ppa_addr)];
+   pos = pblk_ppa_to_pos(geo, rqd->ppa_addr);
+   chunk = >chks[pos];
+
atomic_dec(>left_seblks);
 
if (rqd->error) {
-   struct ppa_addr *ppa;
-
-   ppa = kmalloc(sizeof(struct ppa_addr), GFP_ATOMIC);
-   if (!ppa)
-   return;
-
-   *ppa = rqd->ppa_addr;
-   pblk_mark_bb(pblk, line, ppa);
+   chunk->state = NVM_CHK_ST_OFFLINE;
+   pblk_mark_bb(pblk, line, rqd->ppa_addr);
+   } else {
+   chunk->state = NVM_CHK_ST_FREE;
}
 
atomic_dec(>inflight_io);
@@ -92,6 +105,49 @@ static void pblk_end_io_erase(struct nvm_rq *rqd)
mempool_free(rqd, pblk->e_rq_pool);
 }
 
+/*
+ * Get information for all chunks from the device.
+ *
+ * The caller is responsible for freeing the returned structure
+ */
+struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk)
+{
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   struct nvm_chk_meta *meta;
+   struct ppa_addr ppa;
+   unsigned long len;
+   int ret;
+
+   ppa.ppa = 0;
+
+   len = geo->all_chunks * sizeof(*meta);
+   meta = kzalloc(len, GFP_KERNEL);
+   if (!meta)
+   return ERR_PTR(-ENOMEM);
+
+   ret = nvm_get_chunk_meta(dev, meta, ppa, geo->all_chunks);
+   if (ret) {
+   kfree(meta);
+   return ERR_PTR(-EIO);
+   }
+
+   return meta;
+}
+
+struct nvm_chk_meta *pblk_chunk_get_off(struct pblk *pblk,
+ struct nvm_chk_meta *meta,
+ struct ppa_addr ppa)
+{
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   int ch_off = ppa.m.grp * geo->num_chk * geo->num_lun;
+   int lun_off = ppa.m.pu * geo->num_chk;
+   int chk_off = ppa.m.chk;
+
+   return meta + ch_off + lun_off + chk_off;
+}
+
 void __pblk_map_invalidate(struct pblk *pblk, struct pblk_line *line,
   u64 paddr)
 {
@@ -1094,10 +1150,34 @@ static int pblk_line_init_bb(struct pblk *pblk, struct 
pblk_line *line,
return 1;
 }
 
+static int pblk_prepare_new_line(struct pblk *pblk, struct pblk_line *line)
+{
+   struct pblk_line_meta *lm = >lm;
+   struct nvm_tgt_dev *dev = pblk->dev;
+   struct nvm_geo *geo = >geo;
+   int blk_to_erase = atomic_read(>blk_in_line);
+   int i;
+
+   for (i = 0; i < lm->blk_per_line; i++) {
+   struct pblk_lun *rlun = >luns[i];
+   int pos = pblk_ppa_to_pos(geo, rlun->bppa);
+   int state = line->chks[pos].state;
+
+   /* Free chunks should not be erased */
+   if (state & NVM_CHK_ST_FREE) {
+   set_bit(pblk_ppa_to_pos(geo, rlun->bppa),
+