2018-02-28 17:12:54

by Javier González

[permalink] [raw]
Subject: [PATCH V4 00/15] lightnvm: pblk: implement 2.0 support

# Changes since V4
- Rebase on top of Matias' for-4.17/core
- Fix pblk's write buffer size when using mw_cuints
- Remove chunk information from pblk's sysfs. We intend to clean up
sysfs, as it is messy as it is now, and use trace points instead. So,
avoid an extra refactoring in the near future.

From Matias:
- Squash geometry patches
- Squash chunk support in lightnvm core
- Use core structure for chunk metadata
- Remove intermediate values for csecs and sos before disk
revalidation.
- Various renamings

# Changes since V3
From Matias:
- Remove nvm_common_geo
- Do appropriate renames when having a single geometry for device and
targets

# Changes since V2:

Apply Matias' feedback:
- Remove generic nvm_id identify structure.
- Do not remap capabilities (cap) to media and controlled capabilities
(mccap). Instead, add a comment to prevent confusion when
crosschecking with 2.0 spec.
- Change maxoc and maxocpu defaults from 1 block to the max number of
blocks.
- Re-implement the generic geometry to use nvm_geo on both device and
targets. Maintain nvm_common_geo to make it easier to copy the common
part of the geometry (without having to overwrite target-specific
fields, which is ugly and error prone). Matias, if you still want to
get rid of this, we can do it.
- Re-order patches with renaming to make them more meaningful. These
belong to the series, since the name changes are motivated by 2.0
inclusions. The only exception would be 36d10bfd3234, but I hope it
is OK I include it here.

Also,
- Eliminate a dependency between luns and lines in the init/exit
refactoring.
- Use the global address format when possible to avoid defaulting on
the 1.2 path. This will safe headaches if the address format changes
at some point.

I took out the patch allowing to do bit shifts on non power-of-2 media
formats on pblk's mapping since it requires touching many places that
are not 2.0 related. I'll submit this separately.

# Changes since V1:

Apply Matias' feedback:
- Rebase on top of Matias' latest patches.
- Use nvme_get_log_ext to submit report chunk and export it.
- Re-write report chunk based on Matias' suggestions. Here, I
maintained the lba interface, but it was necessary to redo the
address formatting to match the chunk log page format. For pblk,
this means a double address transformation, but it enables the
standard path to use lbas, plus, this is not in the fast path.
- Fold address format together with address transformations.
- Split the generic geometry patch in different patches.
- Remove refactoring of ligthnvm's core sysfs.

Feedback not applied:
- Not letting pblk know about 1.2 and 2.0 bad block paths.
Since the interfaces for get/set bad block and report chunk are so
different, moving this logic to core adds assumptions on how the
targets would want to get the data back. A way of doing this is
creating a logical report chunk on the 1.2 path, but this would
mean that values like the wear-index are invalid, which requires
the target knowledge. I'm open to suggestions here.

Also:
- Do some further renamings
- Create a generic address format to make it explicit where we share
1.2 and 2.0 fields to avoid address formatting in the fast path.
- Add new fields to sysfs to complete spec and show major/minor
versions (version and subversion to respect current interface).

Implement 2.0 support in pblk. This includes the address formatting and
mapping paths, as well as the sysfs entries for them.

Javier


Javier González (15):
lightnvm: simplify geometry structure.
lightnvm: add controller capabilities to 2.0
lightnvm: add minor version to generic geometry
lightnvm: add shorten OCSSD version in geo
lightnvm: complete geo structure with maxoc*
lightnvm: normalize geometry nomenclature
lightnvm: add support for 2.0 address format
lightnvm: make address conversions depend on generic device
lightnvm: implement get log report chunk helpers
lightnvm: pblk: check for supported version
lightnvm: pblk: rename ppaf* to addrf*
lightnvn: pblk: use generic address format
lightnvm: pblk: implement get log report chunk
lightnvm: pblk: refactor init/exit sequences
lightnvm: pblk: implement 2.0 support

drivers/lightnvm/core.c | 178 ++++-----
drivers/lightnvm/pblk-core.c | 169 ++++++--
drivers/lightnvm/pblk-gc.c | 2 +-
drivers/lightnvm/pblk-init.c | 838 +++++++++++++++++++++++----------------
drivers/lightnvm/pblk-map.c | 4 +-
drivers/lightnvm/pblk-read.c | 2 +-
drivers/lightnvm/pblk-recovery.c | 14 +-
drivers/lightnvm/pblk-rl.c | 2 +-
drivers/lightnvm/pblk-sysfs.c | 65 ++-
drivers/lightnvm/pblk-write.c | 2 +-
drivers/lightnvm/pblk.h | 242 +++++++----
drivers/nvme/host/core.c | 6 +-
drivers/nvme/host/lightnvm.c | 453 ++++++++++++++-------
drivers/nvme/host/nvme.h | 3 +
include/linux/lightnvm.h | 331 ++++++++++------
15 files changed, 1479 insertions(+), 832 deletions(-)

--
2.7.4



2018-02-28 15:51:15

by Javier González

[permalink] [raw]
Subject: [PATCH 04/15] lightnvm: add shorten OCSSD version in geo

Create a shorten version to use in the generic geometry.

Signed-off-by: Javier González <[email protected]>
---
drivers/nvme/host/lightnvm.c | 6 ++++++
include/linux/lightnvm.h | 8 ++++++++
2 files changed, 14 insertions(+)

diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index a600e70b6e6b..85f336a79cda 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -299,6 +299,9 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
geo->major_ver_id = id->ver_id;
geo->minor_ver_id = 2;

+ /* Set compacted version for upper layers */
+ geo->version = NVM_OCSSD_SPEC_12;
+
geo->nr_chnls = src->num_ch;
geo->nr_luns = src->num_lun;
geo->all_luns = geo->nr_chnls * geo->nr_luns;
@@ -385,6 +388,9 @@ static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
geo->major_ver_id = id->mjr;
geo->minor_ver_id = id->mnr;

+ /* Set compacted version for upper layers */
+ geo->version = NVM_OCSSD_SPEC_20;
+
if (!(geo->major_ver_id == 2 && geo->minor_ver_id == 0)) {
pr_err("nvm: OCSSD version not supported (v%d.%d)\n",
geo->major_ver_id, geo->minor_ver_id);
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 4b2ecbf45fd9..b8bc158a2472 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -23,6 +23,11 @@ enum {
#define NVM_LUN_BITS (8)
#define NVM_CH_BITS (7)

+enum {
+ NVM_OCSSD_SPEC_12 = 12,
+ NVM_OCSSD_SPEC_20 = 20,
+};
+
struct ppa_addr {
/* Generic structure for all addresses */
union {
@@ -266,6 +271,9 @@ struct nvm_geo {
u8 major_ver_id;
u8 minor_ver_id;

+ /* kernel short version */
+ u8 version;
+
/* instance specific geometry */
int nr_chnls;
int nr_luns; /* per channel */
--
2.7.4


2018-02-28 17:09:05

by Javier González

[permalink] [raw]
Subject: [PATCH 11/15] lightnvm: pblk: rename ppaf* to addrf*

In preparation for 2.0 support in pblk, rename variables referring to
the address format to addrf and reserve ppaf for the 1.2 path.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/pblk-init.c | 8 ++++----
drivers/lightnvm/pblk-sysfs.c | 4 ++--
drivers/lightnvm/pblk.h | 16 ++++++++--------
3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index b67b5b11ae16..73b221c69cfd 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -80,7 +80,7 @@ static size_t pblk_trans_map_size(struct pblk *pblk)
{
int entry_size = 8;

- if (pblk->ppaf_bitsize < 32)
+ if (pblk->addrf_len < 32)
entry_size = 4;

return entry_size * pblk->rl.nr_secs;
@@ -198,7 +198,7 @@ static int pblk_set_addrf_12(struct nvm_geo *geo,
return dst->blk_offset + src->blk_len;
}

-static int pblk_set_ppaf(struct pblk *pblk)
+static int pblk_set_addrf(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
@@ -210,7 +210,7 @@ static int pblk_set_ppaf(struct pblk *pblk)
return -EINVAL;
}

- pblk->ppaf_bitsize = pblk_set_addrf_12(geo, (void *)&pblk->ppaf);
+ pblk->addrf_len = pblk_set_addrf_12(geo, (void *)&pblk->addrf);

return 0;
}
@@ -319,7 +319,7 @@ static int pblk_core_init(struct pblk *pblk)
if (!pblk->r_end_wq)
goto free_bb_wq;

- if (pblk_set_ppaf(pblk))
+ if (pblk_set_addrf(pblk))
goto free_r_end_wq;

if (pblk_rwb_init(pblk))
diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
index 462a787893d5..cbb5b6edb7bf 100644
--- a/drivers/lightnvm/pblk-sysfs.c
+++ b/drivers/lightnvm/pblk-sysfs.c
@@ -117,12 +117,12 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
struct nvm_addr_format_12 *geo_ppaf;
ssize_t sz = 0;

- ppaf = (struct nvm_addr_format_12 *)&pblk->ppaf;
+ ppaf = (struct nvm_addr_format_12 *)&pblk->addrf;
geo_ppaf = (struct nvm_addr_format_12 *)&geo->addrf;

sz = snprintf(page, PAGE_SIZE,
"pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
- pblk->ppaf_bitsize,
+ pblk->addrf_len,
ppaf->ch_offset, ppaf->ch_len,
ppaf->lun_offset, ppaf->lun_len,
ppaf->blk_offset, ppaf->blk_len,
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index bae2cc758de8..dd0089fe62b9 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -570,8 +570,8 @@ struct pblk {
struct pblk_line_mgmt l_mg; /* Line management */
struct pblk_line_meta lm; /* Line metadata */

- struct nvm_addr_format ppaf;
- int ppaf_bitsize;
+ struct nvm_addr_format addrf;
+ int addrf_len;

struct pblk_rb rwb;

@@ -948,7 +948,7 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
u64 line_id)
{
struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&pblk->ppaf;
+ (struct nvm_addr_format_12 *)&pblk->addrf;
struct ppa_addr ppa;

ppa.ppa = 0;
@@ -966,7 +966,7 @@ static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
struct ppa_addr p)
{
struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&pblk->ppaf;
+ (struct nvm_addr_format_12 *)&pblk->addrf;
u64 paddr;

paddr = (u64)p.g.ch << ppaf->ch_offset;
@@ -991,7 +991,7 @@ static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
ppa64.c.is_cached = 1;
} else {
struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&pblk->ppaf;
+ (struct nvm_addr_format_12 *)&pblk->addrf;

ppa64.g.ch = (ppa32 & ppaf->ch_mask) >> ppaf->ch_offset;
ppa64.g.lun = (ppa32 & ppaf->lun_mask) >> ppaf->lun_offset;
@@ -1015,7 +1015,7 @@ static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
ppa32 |= 1U << 31;
} else {
struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&pblk->ppaf;
+ (struct nvm_addr_format_12 *)&pblk->addrf;

ppa32 |= ppa64.g.ch << ppaf->ch_offset;
ppa32 |= ppa64.g.lun << ppaf->lun_offset;
@@ -1033,7 +1033,7 @@ static inline struct ppa_addr pblk_trans_map_get(struct pblk *pblk,
{
struct ppa_addr ppa;

- if (pblk->ppaf_bitsize < 32) {
+ if (pblk->addrf_len < 32) {
u32 *map = (u32 *)pblk->trans_map;

ppa = pblk_ppa32_to_ppa64(pblk, map[lba]);
@@ -1049,7 +1049,7 @@ static inline struct ppa_addr pblk_trans_map_get(struct pblk *pblk,
static inline void pblk_trans_map_set(struct pblk *pblk, sector_t lba,
struct ppa_addr ppa)
{
- if (pblk->ppaf_bitsize < 32) {
+ if (pblk->addrf_len < 32) {
u32 *map = (u32 *)pblk->trans_map;

map[lba] = pblk_ppa64_to_ppa32(pblk, ppa);
--
2.7.4


2018-02-28 17:09:40

by Javier González

[permalink] [raw]
Subject: [PATCH 13/15] lightnvm: pblk: implement get log report chunk

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 <[email protected]>
---
drivers/lightnvm/pblk-core.c | 139 +++++++++++++++++++++++----
drivers/lightnvm/pblk-init.c | 223 +++++++++++++++++++++++++++++++------------
drivers/lightnvm/pblk.h | 7 ++
include/linux/lightnvm.h | 13 +++
4 files changed, 301 insertions(+), 81 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 2e10b18b61e3..cd663855ee88 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 = &dev->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(&pblk->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 = &dev->geo;
+ struct nvm_chk_meta *chunk;
struct pblk_line *line;
+ int pos;

line = &pblk->lines[pblk_ppa_to_line(rqd->ppa_addr)];
+ pos = pblk_ppa_to_pos(geo, rqd->ppa_addr);
+ chunk = &line->chks[pos];
+
atomic_dec(&line->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(&pblk->inflight_io);
@@ -92,6 +105,50 @@ 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 = &dev->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) {
+ pr_err("pblk: could not get chunk metadata (%d)\n", 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 = &dev->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 +1151,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 = &pblk->lm;
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ int blk_to_erase = atomic_read(&line->blk_in_line);
+ int i;
+
+ for (i = 0; i < lm->blk_per_line; i++) {
+ struct pblk_lun *rlun = &pblk->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),
+ line->erase_bitmap);
+ blk_to_erase--;
+ }
+ }
+
+ return blk_to_erase;
+}
+
static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
{
struct pblk_line_meta *lm = &pblk->lm;
- int blk_in_line = atomic_read(&line->blk_in_line);
+ int blk_to_erase;

line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_ATOMIC);
if (!line->map_bitmap)
@@ -1110,7 +1191,21 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
return -ENOMEM;
}

+ /* Bad blocks do not need to be erased */
+ bitmap_copy(line->erase_bitmap, line->blk_bitmap, lm->blk_per_line);
+
spin_lock(&line->lock);
+
+ /* If we have not written to this line, we need to mark up free chunks
+ * as already erased
+ */
+ if (line->state == PBLK_LINESTATE_NEW) {
+ blk_to_erase = pblk_prepare_new_line(pblk, line);
+ line->state = PBLK_LINESTATE_FREE;
+ } else {
+ blk_to_erase = atomic_read(&line->blk_in_line);
+ }
+
if (line->state != PBLK_LINESTATE_FREE) {
kfree(line->map_bitmap);
kfree(line->invalid_bitmap);
@@ -1122,15 +1217,12 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)

line->state = PBLK_LINESTATE_OPEN;

- atomic_set(&line->left_eblks, blk_in_line);
- atomic_set(&line->left_seblks, blk_in_line);
+ atomic_set(&line->left_eblks, blk_to_erase);
+ atomic_set(&line->left_seblks, blk_to_erase);

line->meta_distance = lm->meta_distance;
spin_unlock(&line->lock);

- /* Bad blocks do not need to be erased */
- bitmap_copy(line->erase_bitmap, line->blk_bitmap, lm->blk_per_line);
-
kref_init(&line->ref);

return 0;
@@ -1586,12 +1678,14 @@ static void pblk_line_should_sync_meta(struct pblk *pblk)

void pblk_line_close(struct pblk *pblk, struct pblk_line *line)
{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_meta *lm = &pblk->lm;
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
struct list_head *move_list;
+ int i;

#ifdef CONFIG_NVM_DEBUG
- struct pblk_line_meta *lm = &pblk->lm;
-
WARN(!bitmap_full(line->map_bitmap, lm->sec_per_line),
"pblk: corrupt closed line %d\n", line->id);
#endif
@@ -1613,6 +1707,15 @@ void pblk_line_close(struct pblk *pblk, struct pblk_line *line)
line->smeta = NULL;
line->emeta = NULL;

+ for (i = 0; i < lm->blk_per_line; i++) {
+ struct pblk_lun *rlun = &pblk->luns[i];
+ int pos = pblk_ppa_to_pos(geo, rlun->bppa);
+ int state = line->chks[pos].state;
+
+ if (!(state & NVM_CHK_ST_OFFLINE))
+ state = NVM_CHK_ST_CLOSED;
+ }
+
spin_unlock(&line->lock);
spin_unlock(&l_mg->gc_lock);
}
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 73b221c69cfd..bd2592fc3378 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -401,6 +401,7 @@ static void pblk_line_meta_free(struct pblk_line *line)
{
kfree(line->blk_bitmap);
kfree(line->erase_bitmap);
+ kfree(line->chks);
}

static void pblk_lines_free(struct pblk *pblk)
@@ -440,55 +441,44 @@ static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
return 0;
}

-static void *pblk_bb_get_log(struct pblk *pblk)
+static void *pblk_bb_get_meta(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- u8 *log;
+ u8 *meta;
int i, nr_blks, blk_per_lun;
int ret;

blk_per_lun = geo->num_chk * geo->pln_mode;
nr_blks = blk_per_lun * geo->all_luns;

- log = kmalloc(nr_blks, GFP_KERNEL);
- if (!log)
+ meta = kmalloc(nr_blks, GFP_KERNEL);
+ if (!meta)
return ERR_PTR(-ENOMEM);

for (i = 0; i < geo->all_luns; i++) {
struct pblk_lun *rlun = &pblk->luns[i];
- u8 *log_pos = log + i * blk_per_lun;
+ u8 *meta_pos = meta + i * blk_per_lun;

- ret = pblk_bb_get_tbl(dev, rlun, log_pos, blk_per_lun);
+ ret = pblk_bb_get_tbl(dev, rlun, meta_pos, blk_per_lun);
if (ret) {
- kfree(log);
+ kfree(meta);
return ERR_PTR(-EIO);
}
}

- return log;
+ return meta;
}

-static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line,
- u8 *bb_log, int blk_per_line)
+static void *pblk_chunk_get_meta(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- int i, bb_cnt = 0;
- int blk_per_lun = geo->num_chk * geo->pln_mode;

- for (i = 0; i < blk_per_line; i++) {
- struct pblk_lun *rlun = &pblk->luns[i];
- u8 *lun_bb_log = bb_log + i * blk_per_lun;
-
- if (lun_bb_log[line->id] == NVM_BLK_T_FREE)
- continue;
-
- set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap);
- bb_cnt++;
- }
-
- return bb_cnt;
+ if (geo->version == NVM_OCSSD_SPEC_12)
+ return pblk_bb_get_meta(pblk);
+ else
+ return pblk_chunk_get_info(pblk);
}

static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
@@ -696,8 +686,131 @@ static int pblk_lines_alloc_metadata(struct pblk *pblk)
return -ENOMEM;
}

-static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
- void *chunk_log, long *nr_bad_blks)
+static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line,
+ void *chunk_meta)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_meta *lm = &pblk->lm;
+ int i, chk_per_lun, nr_bad_chks = 0;
+
+ chk_per_lun = geo->num_chk * geo->pln_mode;
+
+ for (i = 0; i < lm->blk_per_line; i++) {
+ struct pblk_lun *rlun = &pblk->luns[i];
+ struct nvm_chk_meta *chunk;
+ int pos = pblk_ppa_to_pos(geo, rlun->bppa);
+ u8 *lun_bb_meta = chunk_meta + pos * chk_per_lun;
+
+ chunk = &line->chks[pos];
+
+ /*
+ * In 1.2 spec. chunk state is not persisted by the device. Thus
+ * some of the values are reset each time pblk is instantiated.
+ */
+ if (lun_bb_meta[line->id] == NVM_BLK_T_FREE)
+ chunk->state = NVM_CHK_ST_FREE;
+ else
+ chunk->state = NVM_CHK_ST_OFFLINE;
+
+ chunk->type = NVM_CHK_TP_W_SEQ;
+ chunk->wi = 0;
+ chunk->slba = -1;
+ chunk->cnlb = geo->clba;
+ chunk->wp = 0;
+
+ if (!(chunk->state & NVM_CHK_ST_OFFLINE))
+ continue;
+
+ set_bit(pos, line->blk_bitmap);
+ nr_bad_chks++;
+ }
+
+ return nr_bad_chks;
+}
+
+static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
+ struct nvm_chk_meta *meta)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_meta *lm = &pblk->lm;
+ int i, nr_bad_chks = 0;
+
+ for (i = 0; i < lm->blk_per_line; i++) {
+ struct pblk_lun *rlun = &pblk->luns[i];
+ struct nvm_chk_meta *chunk;
+ struct nvm_chk_meta *chunk_meta;
+ struct ppa_addr ppa;
+ int pos;
+
+ ppa = rlun->bppa;
+ pos = pblk_ppa_to_pos(geo, ppa);
+ chunk = &line->chks[pos];
+
+ ppa.m.chk = line->id;
+ chunk_meta = pblk_chunk_get_off(pblk, meta, ppa);
+
+ chunk->state = chunk_meta->state;
+ chunk->type = chunk_meta->type;
+ chunk->wi = chunk_meta->wi;
+ chunk->slba = chunk_meta->slba;
+ chunk->cnlb = chunk_meta->cnlb;
+ chunk->wp = chunk_meta->wp;
+
+ if (!(chunk->state & NVM_CHK_ST_OFFLINE))
+ continue;
+
+ if (chunk->type & NVM_CHK_TP_SZ_SPEC) {
+ WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n");
+ continue;
+ }
+
+ set_bit(pos, line->blk_bitmap);
+ nr_bad_chks++;
+ }
+
+ return nr_bad_chks;
+}
+
+static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
+ void *chunk_meta, int line_id)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_mgmt *l_mg = &pblk->l_mg;
+ struct pblk_line_meta *lm = &pblk->lm;
+ long nr_bad_chks, chk_in_line;
+
+ line->pblk = pblk;
+ line->id = line_id;
+ line->type = PBLK_LINETYPE_FREE;
+ line->state = PBLK_LINESTATE_NEW;
+ line->gc_group = PBLK_LINEGC_NONE;
+ line->vsc = &l_mg->vsc_list[line_id];
+ spin_lock_init(&line->lock);
+
+ if (geo->version == NVM_OCSSD_SPEC_12)
+ nr_bad_chks = pblk_setup_line_meta_12(pblk, line, chunk_meta);
+ else
+ nr_bad_chks = pblk_setup_line_meta_20(pblk, line, chunk_meta);
+
+ chk_in_line = lm->blk_per_line - nr_bad_chks;
+ if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line ||
+ chk_in_line < lm->min_blk_line) {
+ line->state = PBLK_LINESTATE_BAD;
+ list_add_tail(&line->list, &l_mg->bad_list);
+ return 0;
+ }
+
+ atomic_set(&line->blk_in_line, chk_in_line);
+ list_add_tail(&line->list, &l_mg->free_list);
+ l_mg->nr_free_lines++;
+
+ return chk_in_line;
+}
+
+static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line)
{
struct pblk_line_meta *lm = &pblk->lm;

@@ -711,7 +824,13 @@ static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
return -ENOMEM;
}

- *nr_bad_blks = pblk_bb_line(pblk, line, chunk_log, lm->blk_per_line);
+ line->chks = kmalloc(lm->blk_per_line * sizeof(struct nvm_chk_meta),
+ GFP_KERNEL);
+ if (!line->chks) {
+ kfree(line->erase_bitmap);
+ kfree(line->blk_bitmap);
+ return -ENOMEM;
+ }

return 0;
}
@@ -723,9 +842,9 @@ static int pblk_lines_init(struct pblk *pblk)
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
struct pblk_line_meta *lm = &pblk->lm;
struct pblk_line *line;
- void *chunk_log;
+ void *chunk_meta;
unsigned int smeta_len, emeta_len;
- long nr_bad_blks = 0, nr_free_blks = 0;
+ long nr_free_chks = 0;
int bb_distance, max_write_ppas;
int i, ret;

@@ -842,53 +961,31 @@ static int pblk_lines_init(struct pblk *pblk)
goto fail_free_bb_aux;
}

- chunk_log = pblk_bb_get_log(pblk);
- if (IS_ERR(chunk_log)) {
- pr_err("pblk: could not get bad block log (%lu)\n",
- PTR_ERR(chunk_log));
- ret = PTR_ERR(chunk_log);
+ chunk_meta = pblk_chunk_get_meta(pblk);
+ if (IS_ERR(chunk_meta)) {
+ pr_err("pblk: could not get chunk log (%lu)\n",
+ PTR_ERR(chunk_meta));
+ ret = PTR_ERR(chunk_meta);
goto fail_free_lines;
}

for (i = 0; i < l_mg->nr_lines; i++) {
- int chk_in_line;
-
line = &pblk->lines[i];

- line->pblk = pblk;
- line->id = i;
- line->type = PBLK_LINETYPE_FREE;
- line->state = PBLK_LINESTATE_FREE;
- line->gc_group = PBLK_LINEGC_NONE;
- line->vsc = &l_mg->vsc_list[i];
- spin_lock_init(&line->lock);
-
- ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks);
+ ret = pblk_alloc_line_meta(pblk, line);
if (ret)
- goto fail_free_chunk_log;
+ goto fail_free_chunk_meta;

- chk_in_line = lm->blk_per_line - nr_bad_blks;
- if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line ||
- chk_in_line < lm->min_blk_line) {
- line->state = PBLK_LINESTATE_BAD;
- list_add_tail(&line->list, &l_mg->bad_list);
- continue;
- }
-
- nr_free_blks += chk_in_line;
- atomic_set(&line->blk_in_line, chk_in_line);
-
- l_mg->nr_free_lines++;
- list_add_tail(&line->list, &l_mg->free_list);
+ nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
}

- pblk_set_provision(pblk, nr_free_blks);
+ pblk_set_provision(pblk, nr_free_chks);

- kfree(chunk_log);
+ kfree(chunk_meta);
return 0;

-fail_free_chunk_log:
- kfree(chunk_log);
+fail_free_chunk_meta:
+ kfree(chunk_meta);
while (--i >= 0)
pblk_line_meta_free(&pblk->lines[i]);
fail_free_lines:
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 6ac64d9eb57e..ee149766b7a0 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -297,6 +297,7 @@ enum {
PBLK_LINETYPE_DATA = 2,

/* Line state */
+ PBLK_LINESTATE_NEW = 9,
PBLK_LINESTATE_FREE = 10,
PBLK_LINESTATE_OPEN = 11,
PBLK_LINESTATE_CLOSED = 12,
@@ -426,6 +427,8 @@ struct pblk_line {

unsigned long *lun_bitmap; /* Bitmap for LUNs mapped in line */

+ struct nvm_chk_meta *chks; /* Chunks forming line */
+
struct pblk_smeta *smeta; /* Start metadata */
struct pblk_emeta *emeta; /* End medatada */

@@ -729,6 +732,10 @@ void pblk_set_sec_per_write(struct pblk *pblk, int sec_per_write);
int pblk_setup_w_rec_rq(struct pblk *pblk, struct nvm_rq *rqd,
struct pblk_c_ctx *c_ctx);
void pblk_discard(struct pblk *pblk, struct bio *bio);
+struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk);
+struct nvm_chk_meta *pblk_chunk_get_off(struct pblk *pblk,
+ struct nvm_chk_meta *lp,
+ struct ppa_addr ppa);
void pblk_log_write_err(struct pblk *pblk, struct nvm_rq *rqd);
void pblk_log_read_err(struct pblk *pblk, struct nvm_rq *rqd);
int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd);
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 9fe37f7e8185..c120b2243758 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -232,6 +232,19 @@ struct nvm_addr_format {
u64 rsv_mask[2];
};

+enum {
+ /* Chunk states */
+ NVM_CHK_ST_FREE = 1 << 0,
+ NVM_CHK_ST_CLOSED = 1 << 1,
+ NVM_CHK_ST_OPEN = 1 << 2,
+ NVM_CHK_ST_OFFLINE = 1 << 3,
+
+ /* Chunk types */
+ NVM_CHK_TP_W_SEQ = 1 << 0,
+ NVM_CHK_TP_W_RAN = 1 << 1,
+ NVM_CHK_TP_SZ_SPEC = 1 << 4,
+};
+
/*
* Note: The structure size is linked to nvme_nvm_chk_meta such that the same
* buffer can be used when converting from little endian to cpu addressing.
--
2.7.4


2018-02-28 17:09:54

by Javier González

[permalink] [raw]
Subject: [PATCH 15/15] lightnvm: pblk: implement 2.0 support

Implement 2.0 support in pblk. This includes the address formatting and
mapping paths, as well as the sysfs entries for them.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/pblk-init.c | 57 ++++++++++--
drivers/lightnvm/pblk-sysfs.c | 36 ++++++--
drivers/lightnvm/pblk.h | 198 ++++++++++++++++++++++++++++++++----------
3 files changed, 233 insertions(+), 58 deletions(-)

diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index b3e15ef63df3..474f3f047087 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -231,20 +231,63 @@ static int pblk_set_addrf_12(struct nvm_geo *geo,
return dst->blk_offset + src->blk_len;
}

+static int pblk_set_addrf_20(struct nvm_geo *geo,
+ struct nvm_addr_format *adst,
+ struct pblk_addr_format *udst)
+{
+ struct nvm_addr_format *src = &geo->addrf;
+
+ adst->ch_len = get_count_order(geo->num_ch);
+ adst->lun_len = get_count_order(geo->num_lun);
+ adst->chk_len = src->chk_len;
+ adst->sec_len = src->sec_len;
+
+ adst->sec_offset = 0;
+ adst->ch_offset = adst->sec_len;
+ adst->lun_offset = adst->ch_offset + adst->ch_len;
+ adst->chk_offset = adst->lun_offset + adst->lun_len;
+
+ adst->sec_mask = ((1ULL << adst->sec_len) - 1) << adst->sec_offset;
+ adst->chk_mask = ((1ULL << adst->chk_len) - 1) << adst->chk_offset;
+ adst->lun_mask = ((1ULL << adst->lun_len) - 1) << adst->lun_offset;
+ adst->ch_mask = ((1ULL << adst->ch_len) - 1) << adst->ch_offset;
+
+ udst->sec_stripe = geo->ws_opt;
+ udst->ch_stripe = geo->num_ch;
+ udst->lun_stripe = geo->num_lun;
+
+ udst->sec_lun_stripe = udst->sec_stripe * udst->ch_stripe;
+ udst->sec_ws_stripe = udst->sec_lun_stripe * udst->lun_stripe;
+
+ return adst->chk_offset + adst->chk_len;
+}
+
static int pblk_set_addrf(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
int mod;

- div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
- if (mod) {
- pr_err("pblk: bad configuration of sectors/pages\n");
+ switch (geo->version) {
+ case NVM_OCSSD_SPEC_12:
+ div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
+ if (mod) {
+ pr_err("pblk: bad configuration of sectors/pages\n");
+ return -EINVAL;
+ }
+
+ pblk->addrf_len = pblk_set_addrf_12(geo, (void *)&pblk->addrf);
+ break;
+ case NVM_OCSSD_SPEC_20:
+ pblk->addrf_len = pblk_set_addrf_20(geo, (void *)&pblk->addrf,
+ &pblk->uaddrf);
+ break;
+ default:
+ pr_err("pblk: OCSSD revision not supported (%d)\n",
+ geo->version);
return -EINVAL;
}

- pblk->addrf_len = pblk_set_addrf_12(geo, (void *)&pblk->addrf);
-
return 0;
}

@@ -1117,7 +1160,9 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
struct pblk *pblk;
int ret;

- if (geo->version != NVM_OCSSD_SPEC_12) {
+ /* pblk supports 1.2 and 2.0 versions */
+ if (!(geo->version == NVM_OCSSD_SPEC_12 ||
+ geo->version == NVM_OCSSD_SPEC_20)) {
pr_err("pblk: OCSSD version not supported (%u)\n",
geo->version);
return ERR_PTR(-EINVAL);
diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
index a643dc623731..391f865b02d9 100644
--- a/drivers/lightnvm/pblk-sysfs.c
+++ b/drivers/lightnvm/pblk-sysfs.c
@@ -113,15 +113,16 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- struct nvm_addr_format_12 *ppaf;
- struct nvm_addr_format_12 *geo_ppaf;
ssize_t sz = 0;

- ppaf = (struct nvm_addr_format_12 *)&pblk->addrf;
- geo_ppaf = (struct nvm_addr_format_12 *)&geo->addrf;
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&pblk->addrf;
+ struct nvm_addr_format_12 *geo_ppaf =
+ (struct nvm_addr_format_12 *)&geo->addrf;

- sz = snprintf(page, PAGE_SIZE,
- "pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
+ sz = snprintf(page, PAGE_SIZE,
+ "pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
pblk->addrf_len,
ppaf->ch_offset, ppaf->ch_len,
ppaf->lun_offset, ppaf->lun_len,
@@ -130,14 +131,33 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
ppaf->pln_offset, ppaf->pln_len,
ppaf->sec_offset, ppaf->sec_len);

- sz += snprintf(page + sz, PAGE_SIZE - sz,
- "device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
+ sz += snprintf(page + sz, PAGE_SIZE - sz,
+ "device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
geo_ppaf->ch_offset, geo_ppaf->ch_len,
geo_ppaf->lun_offset, geo_ppaf->lun_len,
geo_ppaf->blk_offset, geo_ppaf->blk_len,
geo_ppaf->pg_offset, geo_ppaf->pg_len,
geo_ppaf->pln_offset, geo_ppaf->pln_len,
geo_ppaf->sec_offset, geo_ppaf->sec_len);
+ } else {
+ struct nvm_addr_format *ppaf = &pblk->addrf;
+ struct nvm_addr_format *geo_ppaf = &geo->addrf;
+
+ sz = snprintf(page, PAGE_SIZE,
+ "pblk:(s:%d)ch:%d/%d,lun:%d/%d,chk:%d/%d/sec:%d/%d\n",
+ pblk->addrf_len,
+ ppaf->ch_offset, ppaf->ch_len,
+ ppaf->lun_offset, ppaf->lun_len,
+ ppaf->chk_offset, ppaf->chk_len,
+ ppaf->sec_offset, ppaf->sec_len);
+
+ sz += snprintf(page + sz, PAGE_SIZE - sz,
+ "device:ch:%d/%d,lun:%d/%d,chk:%d/%d,sec:%d/%d\n",
+ geo_ppaf->ch_offset, geo_ppaf->ch_len,
+ geo_ppaf->lun_offset, geo_ppaf->lun_len,
+ geo_ppaf->chk_offset, geo_ppaf->chk_len,
+ geo_ppaf->sec_offset, geo_ppaf->sec_len);
+ }

return sz;
}
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index ee149766b7a0..1deddd38c0ac 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -561,6 +561,18 @@ enum {
PBLK_STATE_STOPPED = 3,
};

+/* Internal format to support not power-of-2 device formats */
+struct pblk_addr_format {
+ /* gen to dev */
+ int sec_stripe;
+ int ch_stripe;
+ int lun_stripe;
+
+ /* dev to gen */
+ int sec_lun_stripe;
+ int sec_ws_stripe;
+};
+
struct pblk {
struct nvm_tgt_dev *dev;
struct gendisk *disk;
@@ -573,7 +585,8 @@ struct pblk {
struct pblk_line_mgmt l_mg; /* Line management */
struct pblk_line_meta lm; /* Line metadata */

- struct nvm_addr_format addrf;
+ struct nvm_addr_format addrf; /* Aligned address format */
+ struct pblk_addr_format uaddrf; /* Unaligned address format */
int addrf_len;

struct pblk_rb rwb;
@@ -954,17 +967,43 @@ static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
u64 line_id)
{
- struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&pblk->addrf;
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
struct ppa_addr ppa;

- ppa.ppa = 0;
- ppa.g.blk = line_id;
- ppa.g.pg = (paddr & ppaf->pg_mask) >> ppaf->pg_offset;
- ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
- ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
- ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
- ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sec_offset;
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&pblk->addrf;
+
+ ppa.ppa = 0;
+ ppa.g.blk = line_id;
+ ppa.g.pg = (paddr & ppaf->pg_mask) >> ppaf->pg_offset;
+ ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
+ ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
+ ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
+ ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sec_offset;
+ } else {
+ struct pblk_addr_format *uaddrf = &pblk->uaddrf;
+ int secs, chnls, luns;
+
+ ppa.ppa = 0;
+
+ ppa.m.chk = line_id;
+
+ div_u64_rem(paddr, uaddrf->sec_stripe, &secs);
+ ppa.m.sec = secs;
+
+ sector_div(paddr, uaddrf->sec_stripe);
+ div_u64_rem(paddr, uaddrf->ch_stripe, &chnls);
+ ppa.m.grp = chnls;
+
+ sector_div(paddr, uaddrf->ch_stripe);
+ div_u64_rem(paddr, uaddrf->lun_stripe, &luns);
+ ppa.m.pu = luns;
+
+ sector_div(paddr, uaddrf->lun_stripe);
+ ppa.m.sec += uaddrf->sec_stripe * paddr;
+ }

return ppa;
}
@@ -972,15 +1011,32 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
struct ppa_addr p)
{
- struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&pblk->addrf;
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
u64 paddr;

- paddr = (u64)p.g.ch << ppaf->ch_offset;
- paddr |= (u64)p.g.lun << ppaf->lun_offset;
- paddr |= (u64)p.g.pg << ppaf->pg_offset;
- paddr |= (u64)p.g.pl << ppaf->pln_offset;
- paddr |= (u64)p.g.sec << ppaf->sec_offset;
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&pblk->addrf;
+
+ paddr = (u64)p.g.ch << ppaf->ch_offset;
+ paddr |= (u64)p.g.lun << ppaf->lun_offset;
+ paddr |= (u64)p.g.pg << ppaf->pg_offset;
+ paddr |= (u64)p.g.pl << ppaf->pln_offset;
+ paddr |= (u64)p.g.sec << ppaf->sec_offset;
+ } else {
+ struct pblk_addr_format *uaddrf = &pblk->uaddrf;
+ u64 secs = (u64)p.m.sec;
+ int sec_stripe;
+
+ paddr = (u64)p.m.grp * uaddrf->sec_stripe;
+ paddr += (u64)p.m.pu * uaddrf->sec_lun_stripe;
+
+ div_u64_rem(secs, uaddrf->sec_stripe, &sec_stripe);
+ sector_div(secs, uaddrf->sec_stripe);
+ paddr += secs * uaddrf->sec_ws_stripe;
+ paddr += sec_stripe;
+ }

return paddr;
}
@@ -997,15 +1053,37 @@ static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
ppa64.c.line = ppa32 & ((~0U) >> 1);
ppa64.c.is_cached = 1;
} else {
- struct nvm_addr_format_12 *ppaf =
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ struct nvm_addr_format_12 *ppaf =
(struct nvm_addr_format_12 *)&pblk->addrf;

- ppa64.g.ch = (ppa32 & ppaf->ch_mask) >> ppaf->ch_offset;
- ppa64.g.lun = (ppa32 & ppaf->lun_mask) >> ppaf->lun_offset;
- ppa64.g.blk = (ppa32 & ppaf->blk_mask) >> ppaf->blk_offset;
- ppa64.g.pg = (ppa32 & ppaf->pg_mask) >> ppaf->pg_offset;
- ppa64.g.pl = (ppa32 & ppaf->pln_mask) >> ppaf->pln_offset;
- ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> ppaf->sec_offset;
+ ppa64.g.ch = (ppa32 & ppaf->ch_mask) >>
+ ppaf->ch_offset;
+ ppa64.g.lun = (ppa32 & ppaf->lun_mask) >>
+ ppaf->lun_offset;
+ ppa64.g.blk = (ppa32 & ppaf->blk_mask) >>
+ ppaf->blk_offset;
+ ppa64.g.pg = (ppa32 & ppaf->pg_mask) >>
+ ppaf->pg_offset;
+ ppa64.g.pl = (ppa32 & ppaf->pln_mask) >>
+ ppaf->pln_offset;
+ ppa64.g.sec = (ppa32 & ppaf->sec_mask) >>
+ ppaf->sec_offset;
+ } else {
+ struct nvm_addr_format *lbaf = &pblk->addrf;
+
+ ppa64.m.grp = (ppa32 & lbaf->ch_mask) >>
+ lbaf->ch_offset;
+ ppa64.m.pu = (ppa32 & lbaf->lun_mask) >>
+ lbaf->lun_offset;
+ ppa64.m.chk = (ppa32 & lbaf->chk_mask) >>
+ lbaf->chk_offset;
+ ppa64.m.sec = (ppa32 & lbaf->sec_mask) >>
+ lbaf->sec_offset;
+ }
}

return ppa64;
@@ -1021,15 +1099,27 @@ static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
ppa32 |= ppa64.c.line;
ppa32 |= 1U << 31;
} else {
- struct nvm_addr_format_12 *ppaf =
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ struct nvm_addr_format_12 *ppaf =
(struct nvm_addr_format_12 *)&pblk->addrf;

- ppa32 |= ppa64.g.ch << ppaf->ch_offset;
- ppa32 |= ppa64.g.lun << ppaf->lun_offset;
- ppa32 |= ppa64.g.blk << ppaf->blk_offset;
- ppa32 |= ppa64.g.pg << ppaf->pg_offset;
- ppa32 |= ppa64.g.pl << ppaf->pln_offset;
- ppa32 |= ppa64.g.sec << ppaf->sec_offset;
+ ppa32 |= ppa64.g.ch << ppaf->ch_offset;
+ ppa32 |= ppa64.g.lun << ppaf->lun_offset;
+ ppa32 |= ppa64.g.blk << ppaf->blk_offset;
+ ppa32 |= ppa64.g.pg << ppaf->pg_offset;
+ ppa32 |= ppa64.g.pl << ppaf->pln_offset;
+ ppa32 |= ppa64.g.sec << ppaf->sec_offset;
+ } else {
+ struct nvm_addr_format *lbaf = &pblk->addrf;
+
+ ppa32 |= ppa64.m.grp << lbaf->ch_offset;
+ ppa32 |= ppa64.m.pu << lbaf->lun_offset;
+ ppa32 |= ppa64.m.chk << lbaf->chk_offset;
+ ppa32 |= ppa64.m.sec << lbaf->sec_offset;
+ }
}

return ppa32;
@@ -1147,6 +1237,9 @@ static inline int pblk_set_progr_mode(struct pblk *pblk, int type)
struct nvm_geo *geo = &dev->geo;
int flags;

+ if (geo->version == NVM_OCSSD_SPEC_20)
+ return 0;
+
flags = geo->pln_mode >> 1;

if (type == PBLK_WRITE)
@@ -1166,6 +1259,9 @@ static inline int pblk_set_read_mode(struct pblk *pblk, int type)
struct nvm_geo *geo = &dev->geo;
int flags;

+ if (geo->version == NVM_OCSSD_SPEC_20)
+ return 0;
+
flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
if (type == PBLK_READ_SEQUENTIAL)
flags |= geo->pln_mode >> 1;
@@ -1179,16 +1275,21 @@ static inline int pblk_io_aligned(struct pblk *pblk, int nr_secs)
}

#ifdef CONFIG_NVM_DEBUG
-static inline void print_ppa(struct ppa_addr *p, char *msg, int error)
+static inline void print_ppa(struct nvm_geo *geo, struct ppa_addr *p,
+ char *msg, int error)
{
if (p->c.is_cached) {
pr_err("ppa: (%s: %x) cache line: %llu\n",
msg, error, (u64)p->c.line);
- } else {
+ } else if (geo->version == NVM_OCSSD_SPEC_12) {
pr_err("ppa: (%s: %x):ch:%d,lun:%d,blk:%d,pg:%d,pl:%d,sec:%d\n",
msg, error,
p->g.ch, p->g.lun, p->g.blk,
p->g.pg, p->g.pl, p->g.sec);
+ } else {
+ pr_err("ppa: (%s: %x):ch:%d,lun:%d,chk:%d,sec:%d\n",
+ msg, error,
+ p->m.grp, p->m.pu, p->m.chk, p->m.sec);
}
}

@@ -1198,13 +1299,13 @@ static inline void pblk_print_failed_rqd(struct pblk *pblk, struct nvm_rq *rqd,
int bit = -1;

if (rqd->nr_ppas == 1) {
- print_ppa(&rqd->ppa_addr, "rqd", error);
+ print_ppa(&pblk->dev->geo, &rqd->ppa_addr, "rqd", error);
return;
}

while ((bit = find_next_bit((void *)&rqd->ppa_status, rqd->nr_ppas,
bit + 1)) < rqd->nr_ppas) {
- print_ppa(&rqd->ppa_list[bit], "rqd", error);
+ print_ppa(&pblk->dev->geo, &rqd->ppa_list[bit], "rqd", error);
}

pr_err("error:%d, ppa_status:%llx\n", error, rqd->ppa_status);
@@ -1220,16 +1321,25 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev,
for (i = 0; i < nr_ppas; i++) {
ppa = &ppas[i];

- if (!ppa->c.is_cached &&
- ppa->g.ch < geo->num_ch &&
- ppa->g.lun < geo->num_lun &&
- ppa->g.pl < geo->num_pln &&
- ppa->g.blk < geo->num_chk &&
- ppa->g.pg < geo->num_pg &&
- ppa->g.sec < geo->ws_min)
- continue;
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ if (!ppa->c.is_cached &&
+ ppa->g.ch < geo->num_ch &&
+ ppa->g.lun < geo->num_lun &&
+ ppa->g.pl < geo->num_pln &&
+ ppa->g.blk < geo->num_chk &&
+ ppa->g.pg < geo->num_pg &&
+ ppa->g.sec < geo->ws_min)
+ continue;
+ } else {
+ if (!ppa->c.is_cached &&
+ ppa->m.grp < geo->num_ch &&
+ ppa->m.pu < geo->num_lun &&
+ ppa->m.chk < geo->num_chk &&
+ ppa->m.sec < geo->clba)
+ continue;
+ }

- print_ppa(ppa, "boundary", i);
+ print_ppa(geo, ppa, "boundary", i);

return 1;
}
--
2.7.4


2018-02-28 17:10:08

by Javier González

[permalink] [raw]
Subject: [PATCH 14/15] lightnvm: pblk: refactor init/exit sequences

Refactor init and exit sequences to improve readability. In the way, fix
bad free ordering on the init error path.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/pblk-init.c | 533 +++++++++++++++++++++----------------------
1 file changed, 266 insertions(+), 267 deletions(-)

diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index bd2592fc3378..b3e15ef63df3 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -103,7 +103,40 @@ static void pblk_l2p_free(struct pblk *pblk)
vfree(pblk->trans_map);
}

-static int pblk_l2p_init(struct pblk *pblk)
+static int pblk_l2p_recover(struct pblk *pblk, bool factory_init)
+{
+ struct pblk_line *line = NULL;
+
+ if (factory_init) {
+ pblk_setup_uuid(pblk);
+ } else {
+ line = pblk_recov_l2p(pblk);
+ if (IS_ERR(line)) {
+ pr_err("pblk: could not recover l2p table\n");
+ return -EFAULT;
+ }
+ }
+
+#ifdef CONFIG_NVM_DEBUG
+ pr_info("pblk init: L2P CRC: %x\n", pblk_l2p_crc(pblk));
+#endif
+
+ /* Free full lines directly as GC has not been started yet */
+ pblk_gc_free_full_lines(pblk);
+
+ if (!line) {
+ /* Configure next line for user data */
+ line = pblk_line_get_first_data(pblk);
+ if (!line) {
+ pr_err("pblk: line list corrupted\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int pblk_l2p_init(struct pblk *pblk, bool factory_init)
{
sector_t i;
struct ppa_addr ppa;
@@ -119,7 +152,7 @@ static int pblk_l2p_init(struct pblk *pblk)
for (i = 0; i < pblk->rl.nr_secs; i++)
pblk_trans_map_set(pblk, i, ppa);

- return 0;
+ return pblk_l2p_recover(pblk, factory_init);
}

static void pblk_rwb_free(struct pblk *pblk)
@@ -268,86 +301,113 @@ static int pblk_core_init(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
+ int max_write_ppas;
+
+ atomic64_set(&pblk->user_wa, 0);
+ atomic64_set(&pblk->pad_wa, 0);
+ atomic64_set(&pblk->gc_wa, 0);
+ pblk->user_rst_wa = 0;
+ pblk->pad_rst_wa = 0;
+ pblk->gc_rst_wa = 0;
+
+ atomic_long_set(&pblk->nr_flush, 0);
+ pblk->nr_flush_rst = 0;

pblk->pgs_in_buffer = geo->mw_cunits * geo->all_luns;

+ pblk->min_write_pgs = geo->ws_opt * (geo->csecs / PAGE_SIZE);
+ max_write_ppas = pblk->min_write_pgs * geo->all_luns;
+ pblk->max_write_pgs = (max_write_ppas < NVM_MAX_VLBA) ?
+ max_write_ppas : NVM_MAX_VLBA;
+ pblk_set_sec_per_write(pblk, pblk->min_write_pgs);
+
+ if (pblk->max_write_pgs > PBLK_MAX_REQ_ADDRS) {
+ pr_err("pblk: cannot support device max_phys_sect\n");
+ return -EINVAL;
+ }
+
+ pblk->pad_dist = kzalloc((pblk->min_write_pgs - 1) * sizeof(atomic64_t),
+ GFP_KERNEL);
+ if (!pblk->pad_dist)
+ return -ENOMEM;
+
if (pblk_init_global_caches(pblk))
- return -ENOMEM;
+ goto fail_free_pad_dist;

/* Internal bios can be at most the sectors signaled by the device. */
pblk->page_bio_pool = mempool_create_page_pool(NVM_MAX_VLBA, 0);
if (!pblk->page_bio_pool)
- goto free_global_caches;
+ goto fail_free_global_caches;

pblk->gen_ws_pool = mempool_create_slab_pool(PBLK_GEN_WS_POOL_SIZE,
pblk_ws_cache);
if (!pblk->gen_ws_pool)
- goto free_page_bio_pool;
+ goto fail_free_page_bio_pool;

pblk->rec_pool = mempool_create_slab_pool(geo->all_luns,
pblk_rec_cache);
if (!pblk->rec_pool)
- goto free_gen_ws_pool;
+ goto fail_free_gen_ws_pool;

pblk->r_rq_pool = mempool_create_slab_pool(geo->all_luns,
pblk_g_rq_cache);
if (!pblk->r_rq_pool)
- goto free_rec_pool;
+ goto fail_free_rec_pool;

pblk->e_rq_pool = mempool_create_slab_pool(geo->all_luns,
pblk_g_rq_cache);
if (!pblk->e_rq_pool)
- goto free_r_rq_pool;
+ goto fail_free_r_rq_pool;

pblk->w_rq_pool = mempool_create_slab_pool(geo->all_luns,
pblk_w_rq_cache);
if (!pblk->w_rq_pool)
- goto free_e_rq_pool;
+ goto fail_free_e_rq_pool;

pblk->close_wq = alloc_workqueue("pblk-close-wq",
WQ_MEM_RECLAIM | WQ_UNBOUND, PBLK_NR_CLOSE_JOBS);
if (!pblk->close_wq)
- goto free_w_rq_pool;
+ goto fail_free_w_rq_pool;

pblk->bb_wq = alloc_workqueue("pblk-bb-wq",
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
if (!pblk->bb_wq)
- goto free_close_wq;
+ goto fail_free_close_wq;

pblk->r_end_wq = alloc_workqueue("pblk-read-end-wq",
WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
if (!pblk->r_end_wq)
- goto free_bb_wq;
+ goto fail_free_bb_wq;

if (pblk_set_addrf(pblk))
- goto free_r_end_wq;
-
- if (pblk_rwb_init(pblk))
- goto free_r_end_wq;
+ goto fail_free_r_end_wq;

INIT_LIST_HEAD(&pblk->compl_list);
+
return 0;

-free_r_end_wq:
+fail_free_r_end_wq:
destroy_workqueue(pblk->r_end_wq);
-free_bb_wq:
+fail_free_bb_wq:
destroy_workqueue(pblk->bb_wq);
-free_close_wq:
+fail_free_close_wq:
destroy_workqueue(pblk->close_wq);
-free_w_rq_pool:
+fail_free_w_rq_pool:
mempool_destroy(pblk->w_rq_pool);
-free_e_rq_pool:
+fail_free_e_rq_pool:
mempool_destroy(pblk->e_rq_pool);
-free_r_rq_pool:
+fail_free_r_rq_pool:
mempool_destroy(pblk->r_rq_pool);
-free_rec_pool:
+fail_free_rec_pool:
mempool_destroy(pblk->rec_pool);
-free_gen_ws_pool:
+fail_free_gen_ws_pool:
mempool_destroy(pblk->gen_ws_pool);
-free_page_bio_pool:
+fail_free_page_bio_pool:
mempool_destroy(pblk->page_bio_pool);
-free_global_caches:
+fail_free_global_caches:
pblk_free_global_caches(pblk);
+fail_free_pad_dist:
+ kfree(pblk->pad_dist);
return -ENOMEM;
}

@@ -369,14 +429,8 @@ static void pblk_core_free(struct pblk *pblk)
mempool_destroy(pblk->e_rq_pool);
mempool_destroy(pblk->w_rq_pool);

- pblk_rwb_free(pblk);
-
pblk_free_global_caches(pblk);
-}
-
-static void pblk_luns_free(struct pblk *pblk)
-{
- kfree(pblk->luns);
+ kfree(pblk->pad_dist);
}

static void pblk_line_mg_free(struct pblk *pblk)
@@ -393,8 +447,6 @@ static void pblk_line_mg_free(struct pblk *pblk)
pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type);
kfree(l_mg->eline_meta[i]);
}
-
- kfree(pblk->lines);
}

static void pblk_line_meta_free(struct pblk_line *line)
@@ -418,6 +470,11 @@ static void pblk_lines_free(struct pblk *pblk)
pblk_line_meta_free(line);
}
spin_unlock(&l_mg->free_lock);
+
+ pblk_line_mg_free(pblk);
+
+ kfree(pblk->luns);
+ kfree(pblk->lines);
}

static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
@@ -481,7 +538,7 @@ static void *pblk_chunk_get_meta(struct pblk *pblk)
return pblk_chunk_get_info(pblk);
}

-static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
+static int pblk_luns_init(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
@@ -494,11 +551,6 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
return -EINVAL;
}

- pblk->luns = kcalloc(geo->all_luns, sizeof(struct pblk_lun),
- GFP_KERNEL);
- if (!pblk->luns)
- return -ENOMEM;
-
for (i = 0; i < geo->all_luns; i++) {
/* Stripe across channels */
int ch = i % geo->num_ch;
@@ -506,7 +558,7 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
int lunid = lun_raw + ch * geo->num_lun;

rlun = &pblk->luns[i];
- rlun->bppa = luns[lunid];
+ rlun->bppa = dev->luns[lunid];

sema_init(&rlun->wr_sem, 1);
}
@@ -514,38 +566,6 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
return 0;
}

-static int pblk_lines_configure(struct pblk *pblk, int flags)
-{
- struct pblk_line *line = NULL;
- int ret = 0;
-
- if (!(flags & NVM_TARGET_FACTORY)) {
- line = pblk_recov_l2p(pblk);
- if (IS_ERR(line)) {
- pr_err("pblk: could not recover l2p table\n");
- ret = -EFAULT;
- }
- }
-
-#ifdef CONFIG_NVM_DEBUG
- pr_info("pblk init: L2P CRC: %x\n", pblk_l2p_crc(pblk));
-#endif
-
- /* Free full lines directly as GC has not been started yet */
- pblk_gc_free_full_lines(pblk);
-
- if (!line) {
- /* Configure next line for user data */
- line = pblk_line_get_first_data(pblk);
- if (!line) {
- pr_err("pblk: line list corrupted\n");
- ret = -EFAULT;
- }
- }
-
- return ret;
-}
-
/* See comment over struct line_emeta definition */
static unsigned int calc_emeta_len(struct pblk *pblk)
{
@@ -611,81 +631,6 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
}

-static int pblk_lines_alloc_metadata(struct pblk *pblk)
-{
- struct pblk_line_mgmt *l_mg = &pblk->l_mg;
- struct pblk_line_meta *lm = &pblk->lm;
- int i;
-
- /* smeta is always small enough to fit on a kmalloc memory allocation,
- * emeta depends on the number of LUNs allocated to the pblk instance
- */
- for (i = 0; i < PBLK_DATA_LINES; i++) {
- l_mg->sline_meta[i] = kmalloc(lm->smeta_len, GFP_KERNEL);
- if (!l_mg->sline_meta[i])
- goto fail_free_smeta;
- }
-
- /* emeta allocates three different buffers for managing metadata with
- * in-memory and in-media layouts
- */
- for (i = 0; i < PBLK_DATA_LINES; i++) {
- struct pblk_emeta *emeta;
-
- emeta = kmalloc(sizeof(struct pblk_emeta), GFP_KERNEL);
- if (!emeta)
- goto fail_free_emeta;
-
- if (lm->emeta_len[0] > KMALLOC_MAX_CACHE_SIZE) {
- l_mg->emeta_alloc_type = PBLK_VMALLOC_META;
-
- emeta->buf = vmalloc(lm->emeta_len[0]);
- if (!emeta->buf) {
- kfree(emeta);
- goto fail_free_emeta;
- }
-
- emeta->nr_entries = lm->emeta_sec[0];
- l_mg->eline_meta[i] = emeta;
- } else {
- l_mg->emeta_alloc_type = PBLK_KMALLOC_META;
-
- emeta->buf = kmalloc(lm->emeta_len[0], GFP_KERNEL);
- if (!emeta->buf) {
- kfree(emeta);
- goto fail_free_emeta;
- }
-
- emeta->nr_entries = lm->emeta_sec[0];
- l_mg->eline_meta[i] = emeta;
- }
- }
-
- l_mg->vsc_list = kcalloc(l_mg->nr_lines, sizeof(__le32), GFP_KERNEL);
- if (!l_mg->vsc_list)
- goto fail_free_emeta;
-
- for (i = 0; i < l_mg->nr_lines; i++)
- l_mg->vsc_list[i] = cpu_to_le32(EMPTY_ENTRY);
-
- return 0;
-
-fail_free_emeta:
- while (--i >= 0) {
- if (l_mg->emeta_alloc_type == PBLK_VMALLOC_META)
- vfree(l_mg->eline_meta[i]->buf);
- else
- kfree(l_mg->eline_meta[i]->buf);
- kfree(l_mg->eline_meta[i]);
- }
-
-fail_free_smeta:
- for (i = 0; i < PBLK_DATA_LINES; i++)
- kfree(l_mg->sline_meta[i]);
-
- return -ENOMEM;
-}
-
static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line,
void *chunk_meta)
{
@@ -835,29 +780,13 @@ static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line)
return 0;
}

-static int pblk_lines_init(struct pblk *pblk)
+static int pblk_line_mg_init(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
struct pblk_line_meta *lm = &pblk->lm;
- struct pblk_line *line;
- void *chunk_meta;
- unsigned int smeta_len, emeta_len;
- long nr_free_chks = 0;
- int bb_distance, max_write_ppas;
- int i, ret;
-
- pblk->min_write_pgs = geo->ws_opt * (geo->csecs / PAGE_SIZE);
- max_write_ppas = pblk->min_write_pgs * geo->all_luns;
- pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA);
- pblk_set_sec_per_write(pblk, pblk->min_write_pgs);
-
- if (pblk->max_write_pgs > PBLK_MAX_REQ_ADDRS) {
- pr_err("pblk: vector list too big(%u > %u)\n",
- pblk->max_write_pgs, PBLK_MAX_REQ_ADDRS);
- return -EINVAL;
- }
+ int i, bb_distance;

l_mg->nr_lines = geo->num_chk;
l_mg->log_line = l_mg->data_line = NULL;
@@ -865,6 +794,119 @@ static int pblk_lines_init(struct pblk *pblk)
l_mg->nr_free_lines = 0;
bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES);

+ INIT_LIST_HEAD(&l_mg->free_list);
+ INIT_LIST_HEAD(&l_mg->corrupt_list);
+ INIT_LIST_HEAD(&l_mg->bad_list);
+ INIT_LIST_HEAD(&l_mg->gc_full_list);
+ INIT_LIST_HEAD(&l_mg->gc_high_list);
+ INIT_LIST_HEAD(&l_mg->gc_mid_list);
+ INIT_LIST_HEAD(&l_mg->gc_low_list);
+ INIT_LIST_HEAD(&l_mg->gc_empty_list);
+
+ INIT_LIST_HEAD(&l_mg->emeta_list);
+
+ l_mg->gc_lists[0] = &l_mg->gc_high_list;
+ l_mg->gc_lists[1] = &l_mg->gc_mid_list;
+ l_mg->gc_lists[2] = &l_mg->gc_low_list;
+
+ spin_lock_init(&l_mg->free_lock);
+ spin_lock_init(&l_mg->close_lock);
+ spin_lock_init(&l_mg->gc_lock);
+
+ l_mg->vsc_list = kcalloc(l_mg->nr_lines, sizeof(__le32), GFP_KERNEL);
+ if (!l_mg->vsc_list)
+ goto fail;
+
+ l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
+ if (!l_mg->bb_template)
+ goto fail_free_vsc_list;
+
+ l_mg->bb_aux = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
+ if (!l_mg->bb_aux)
+ goto fail_free_bb_template;
+
+ /* smeta is always small enough to fit on a kmalloc memory allocation,
+ * emeta depends on the number of LUNs allocated to the pblk instance
+ */
+ for (i = 0; i < PBLK_DATA_LINES; i++) {
+ l_mg->sline_meta[i] = kmalloc(lm->smeta_len, GFP_KERNEL);
+ if (!l_mg->sline_meta[i])
+ goto fail_free_smeta;
+ }
+
+ /* emeta allocates three different buffers for managing metadata with
+ * in-memory and in-media layouts
+ */
+ for (i = 0; i < PBLK_DATA_LINES; i++) {
+ struct pblk_emeta *emeta;
+
+ emeta = kmalloc(sizeof(struct pblk_emeta), GFP_KERNEL);
+ if (!emeta)
+ goto fail_free_emeta;
+
+ if (lm->emeta_len[0] > KMALLOC_MAX_CACHE_SIZE) {
+ l_mg->emeta_alloc_type = PBLK_VMALLOC_META;
+
+ emeta->buf = vmalloc(lm->emeta_len[0]);
+ if (!emeta->buf) {
+ kfree(emeta);
+ goto fail_free_emeta;
+ }
+
+ emeta->nr_entries = lm->emeta_sec[0];
+ l_mg->eline_meta[i] = emeta;
+ } else {
+ l_mg->emeta_alloc_type = PBLK_KMALLOC_META;
+
+ emeta->buf = kmalloc(lm->emeta_len[0], GFP_KERNEL);
+ if (!emeta->buf) {
+ kfree(emeta);
+ goto fail_free_emeta;
+ }
+
+ emeta->nr_entries = lm->emeta_sec[0];
+ l_mg->eline_meta[i] = emeta;
+ }
+ }
+
+ for (i = 0; i < l_mg->nr_lines; i++)
+ l_mg->vsc_list[i] = cpu_to_le32(EMPTY_ENTRY);
+
+ bb_distance = (geo->all_luns) * geo->ws_opt;
+ for (i = 0; i < lm->sec_per_line; i += bb_distance)
+ bitmap_set(l_mg->bb_template, i, geo->ws_opt);
+
+ return 0;
+
+fail_free_emeta:
+ while (--i >= 0) {
+ if (l_mg->emeta_alloc_type == PBLK_VMALLOC_META)
+ vfree(l_mg->eline_meta[i]->buf);
+ else
+ kfree(l_mg->eline_meta[i]->buf);
+ kfree(l_mg->eline_meta[i]);
+ }
+fail_free_smeta:
+ kfree(l_mg->bb_aux);
+
+ for (i = 0; i < PBLK_DATA_LINES; i++)
+ kfree(l_mg->sline_meta[i]);
+fail_free_bb_template:
+ kfree(l_mg->bb_template);
+fail_free_vsc_list:
+ kfree(l_mg->vsc_list);
+fail:
+ return -ENOMEM;
+}
+
+static int pblk_line_meta_init(struct pblk *pblk)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_meta *lm = &pblk->lm;
+ unsigned int smeta_len, emeta_len;
+ int i;
+
lm->sec_per_line = geo->clba * geo->all_luns;
lm->blk_per_line = geo->all_luns;
lm->blk_bitmap_len = BITS_TO_LONGS(geo->all_luns) * sizeof(long);
@@ -915,58 +957,49 @@ static int pblk_lines_init(struct pblk *pblk)
return -EINVAL;
}

- ret = pblk_lines_alloc_metadata(pblk);
+ return 0;
+}
+
+static int pblk_lines_init(struct pblk *pblk)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_mgmt *l_mg = &pblk->l_mg;
+ struct pblk_line *line;
+ void *chunk_meta;
+ long nr_free_chks = 0;
+ int i, ret;
+
+ ret = pblk_line_meta_init(pblk);
if (ret)
return ret;

- l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
- if (!l_mg->bb_template) {
- ret = -ENOMEM;
- goto fail_free_meta;
- }
-
- l_mg->bb_aux = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
- if (!l_mg->bb_aux) {
- ret = -ENOMEM;
- goto fail_free_bb_template;
- }
-
- bb_distance = (geo->all_luns) * geo->ws_opt;
- for (i = 0; i < lm->sec_per_line; i += bb_distance)
- bitmap_set(l_mg->bb_template, i, geo->ws_opt);
-
- INIT_LIST_HEAD(&l_mg->free_list);
- INIT_LIST_HEAD(&l_mg->corrupt_list);
- INIT_LIST_HEAD(&l_mg->bad_list);
- INIT_LIST_HEAD(&l_mg->gc_full_list);
- INIT_LIST_HEAD(&l_mg->gc_high_list);
- INIT_LIST_HEAD(&l_mg->gc_mid_list);
- INIT_LIST_HEAD(&l_mg->gc_low_list);
- INIT_LIST_HEAD(&l_mg->gc_empty_list);
-
- INIT_LIST_HEAD(&l_mg->emeta_list);
-
- l_mg->gc_lists[0] = &l_mg->gc_high_list;
- l_mg->gc_lists[1] = &l_mg->gc_mid_list;
- l_mg->gc_lists[2] = &l_mg->gc_low_list;
-
- spin_lock_init(&l_mg->free_lock);
- spin_lock_init(&l_mg->close_lock);
- spin_lock_init(&l_mg->gc_lock);
+ ret = pblk_line_mg_init(pblk);
+ if (ret)
+ return ret;

- pblk->lines = kcalloc(l_mg->nr_lines, sizeof(struct pblk_line),
+ pblk->luns = kcalloc(geo->all_luns, sizeof(struct pblk_lun),
GFP_KERNEL);
- if (!pblk->lines) {
- ret = -ENOMEM;
- goto fail_free_bb_aux;
- }
+ if (!pblk->luns)
+ return -ENOMEM;
+
+ ret = pblk_luns_init(pblk);
+ if (ret)
+ goto fail_free_luns;

chunk_meta = pblk_chunk_get_meta(pblk);
if (IS_ERR(chunk_meta)) {
pr_err("pblk: could not get chunk log (%lu)\n",
PTR_ERR(chunk_meta));
ret = PTR_ERR(chunk_meta);
- goto fail_free_lines;
+ goto fail_free_meta;
+ }
+
+ pblk->lines = kcalloc(l_mg->nr_lines, sizeof(struct pblk_line),
+ GFP_KERNEL);
+ if (!pblk->lines) {
+ ret = -ENOMEM;
+ goto fail_free_chunk_meta;
}

for (i = 0; i < l_mg->nr_lines; i++) {
@@ -974,7 +1007,7 @@ static int pblk_lines_init(struct pblk *pblk)

ret = pblk_alloc_line_meta(pblk, line);
if (ret)
- goto fail_free_chunk_meta;
+ goto fail_free_lines;

nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
}
@@ -984,18 +1017,16 @@ static int pblk_lines_init(struct pblk *pblk)
kfree(chunk_meta);
return 0;

-fail_free_chunk_meta:
- kfree(chunk_meta);
+fail_free_lines:
while (--i >= 0)
pblk_line_meta_free(&pblk->lines[i]);
-fail_free_lines:
kfree(pblk->lines);
-fail_free_bb_aux:
- kfree(l_mg->bb_aux);
-fail_free_bb_template:
- kfree(l_mg->bb_template);
+fail_free_chunk_meta:
+ kfree(chunk_meta);
fail_free_meta:
pblk_line_mg_free(pblk);
+fail_free_luns:
+ kfree(pblk->luns);

return ret;
}
@@ -1036,12 +1067,10 @@ static void pblk_writer_stop(struct pblk *pblk)

static void pblk_free(struct pblk *pblk)
{
- pblk_luns_free(pblk);
pblk_lines_free(pblk);
- kfree(pblk->pad_dist);
- pblk_line_mg_free(pblk);
- pblk_core_free(pblk);
pblk_l2p_free(pblk);
+ pblk_rwb_free(pblk);
+ pblk_core_free(pblk);

kfree(pblk);
}
@@ -1112,19 +1141,6 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
spin_lock_init(&pblk->trans_lock);
spin_lock_init(&pblk->lock);

- if (flags & NVM_TARGET_FACTORY)
- pblk_setup_uuid(pblk);
-
- atomic64_set(&pblk->user_wa, 0);
- atomic64_set(&pblk->pad_wa, 0);
- atomic64_set(&pblk->gc_wa, 0);
- pblk->user_rst_wa = 0;
- pblk->pad_rst_wa = 0;
- pblk->gc_rst_wa = 0;
-
- atomic64_set(&pblk->nr_flush, 0);
- pblk->nr_flush_rst = 0;
-
#ifdef CONFIG_NVM_DEBUG
atomic_long_set(&pblk->inflight_writes, 0);
atomic_long_set(&pblk->padded_writes, 0);
@@ -1148,48 +1164,35 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
atomic_long_set(&pblk->write_failed, 0);
atomic_long_set(&pblk->erase_failed, 0);

- ret = pblk_luns_init(pblk, dev->luns);
- if (ret) {
- pr_err("pblk: could not initialize luns\n");
- goto fail;
- }
-
- ret = pblk_lines_init(pblk);
- if (ret) {
- pr_err("pblk: could not initialize lines\n");
- goto fail_free_luns;
- }
-
- pblk->pad_dist = kzalloc((pblk->min_write_pgs - 1) * sizeof(atomic64_t),
- GFP_KERNEL);
- if (!pblk->pad_dist) {
- ret = -ENOMEM;
- goto fail_free_line_meta;
- }
-
ret = pblk_core_init(pblk);
if (ret) {
pr_err("pblk: could not initialize core\n");
- goto fail_free_pad_dist;
+ goto fail;
}

- ret = pblk_l2p_init(pblk);
+ ret = pblk_lines_init(pblk);
if (ret) {
- pr_err("pblk: could not initialize maps\n");
+ pr_err("pblk: could not initialize lines\n");
goto fail_free_core;
}

- ret = pblk_lines_configure(pblk, flags);
+ ret = pblk_rwb_init(pblk);
if (ret) {
- pr_err("pblk: could not configure lines\n");
- goto fail_free_l2p;
+ pr_err("pblk: could not initialize write buffer\n");
+ goto fail_free_lines;
+ }
+
+ ret = pblk_l2p_init(pblk, flags & NVM_TARGET_FACTORY);
+ if (ret) {
+ pr_err("pblk: could not initialize maps\n");
+ goto fail_free_rwb;
}

ret = pblk_writer_init(pblk);
if (ret) {
if (ret != -EINTR)
pr_err("pblk: could not initialize write thread\n");
- goto fail_free_lines;
+ goto fail_free_l2p;
}

ret = pblk_gc_init(pblk);
@@ -1224,18 +1227,14 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,

fail_stop_writer:
pblk_writer_stop(pblk);
-fail_free_lines:
- pblk_lines_free(pblk);
fail_free_l2p:
pblk_l2p_free(pblk);
+fail_free_rwb:
+ pblk_rwb_free(pblk);
+fail_free_lines:
+ pblk_lines_free(pblk);
fail_free_core:
pblk_core_free(pblk);
-fail_free_pad_dist:
- kfree(pblk->pad_dist);
-fail_free_line_meta:
- pblk_line_mg_free(pblk);
-fail_free_luns:
- pblk_luns_free(pblk);
fail:
kfree(pblk);
return ERR_PTR(ret);
--
2.7.4


2018-02-28 17:11:04

by Javier González

[permalink] [raw]
Subject: [PATCH 09/15] lightnvm: implement get log report chunk helpers

The 2.0 spec provides a report chunk log page that can be retrieved
using the stangard nvme get log page. This replaces the dedicated
get/put bad block table in 1.2.

This patch implements the helper functions to allow targets retrieve the
chunk metadata using get log page. It makes nvme_get_log_ext available
outside of nvme core so that we can use it form lightnvm.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/core.c | 11 +++++++
drivers/nvme/host/core.c | 6 ++--
drivers/nvme/host/lightnvm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++
drivers/nvme/host/nvme.h | 3 ++
include/linux/lightnvm.h | 24 ++++++++++++++
5 files changed, 115 insertions(+), 3 deletions(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index ed33e0b11788..4141871f460d 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -712,6 +712,17 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev,
nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list);
}

+int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta,
+ struct ppa_addr ppa, int nchks)
+{
+ struct nvm_dev *dev = tgt_dev->parent;
+
+ nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
+
+ return dev->ops->get_chk_meta(tgt_dev->parent, meta,
+ (sector_t)ppa.ppa, nchks);
+}
+EXPORT_SYMBOL(nvm_get_chunk_meta);

int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
int nr_ppas, int type)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 2e9e9f973a75..af642ce6ba69 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2127,9 +2127,9 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
return ret;
}

-static int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
- u8 log_page, void *log,
- size_t size, size_t offset)
+int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+ u8 log_page, void *log,
+ size_t size, size_t offset)
{
struct nvme_command c = { };
unsigned long dwlen = size / 4 - 1;
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index f7135659f918..a1796241040f 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -35,6 +35,10 @@ enum nvme_nvm_admin_opcode {
nvme_nvm_admin_set_bb_tbl = 0xf1,
};

+enum nvme_nvm_log_page {
+ NVME_NVM_LOG_REPORT_CHUNK = 0xca,
+};
+
struct nvme_nvm_ph_rw {
__u8 opcode;
__u8 flags;
@@ -236,6 +240,16 @@ struct nvme_nvm_id20 {
__u8 vs[1024];
};

+struct nvme_nvm_chk_meta {
+ __u8 state;
+ __u8 type;
+ __u8 wi;
+ __u8 rsvd[5];
+ __le64 slba;
+ __le64 cnlb;
+ __le64 wp;
+};
+
/*
* Check we didn't inadvertently grow the command struct
*/
@@ -252,6 +266,9 @@ static inline void _nvme_nvm_check_size(void)
BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8);
BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != 32);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) !=
+ sizeof(struct nvm_chk_meta));
}

static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
@@ -555,6 +572,61 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas,
return ret;
}

+/*
+ * Expect the lba in device format
+ */
+static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
+ struct nvm_chk_meta *meta,
+ sector_t slba, int nchks)
+{
+ struct nvm_geo *geo = &ndev->geo;
+ struct nvme_ns *ns = ndev->q->queuedata;
+ struct nvme_ctrl *ctrl = ns->ctrl;
+ struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta;
+ struct ppa_addr ppa;
+ size_t left = nchks * sizeof(struct nvme_nvm_chk_meta);
+ size_t log_pos, offset, len;
+ int ret, i;
+
+ /* Normalize lba address space to obtain log offset */
+ ppa.ppa = slba;
+ ppa = dev_to_generic_addr(ndev, ppa);
+
+ log_pos = ppa.m.chk;
+ log_pos += ppa.m.pu * geo->num_chk;
+ log_pos += ppa.m.grp * geo->num_lun * geo->num_chk;
+
+ offset = log_pos * sizeof(struct nvme_nvm_chk_meta);
+
+ while (left) {
+ len = min_t(unsigned int, left, ctrl->max_hw_sectors << 9);
+
+ ret = nvme_get_log_ext(ctrl, ns, NVME_NVM_LOG_REPORT_CHUNK,
+ dev_meta, len, offset);
+ if (ret) {
+ dev_err(ctrl->device, "Get REPORT CHUNK log error\n");
+ break;
+ }
+
+ for (i = 0; i < len; i += sizeof(struct nvme_nvm_chk_meta)) {
+ meta->state = dev_meta->state;
+ meta->type = dev_meta->type;
+ meta->wi = dev_meta->wi;
+ meta->slba = le64_to_cpu(dev_meta->slba);
+ meta->cnlb = le64_to_cpu(dev_meta->cnlb);
+ meta->wp = le64_to_cpu(dev_meta->wp);
+
+ meta++;
+ dev_meta++;
+ }
+
+ offset += len;
+ left -= len;
+ }
+
+ return ret;
+}
+
static inline void nvme_nvm_rqtocmd(struct nvm_rq *rqd, struct nvme_ns *ns,
struct nvme_nvm_command *c)
{
@@ -686,6 +758,8 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
.get_bb_tbl = nvme_nvm_get_bb_tbl,
.set_bb_tbl = nvme_nvm_set_bb_tbl,

+ .get_chk_meta = nvme_nvm_get_chk_meta,
+
.submit_io = nvme_nvm_submit_io,
.submit_io_sync = nvme_nvm_submit_io_sync,

diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 1ca08f4993ba..505f797f8c6c 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -396,6 +396,9 @@ int nvme_reset_ctrl(struct nvme_ctrl *ctrl);
int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
int nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl);

+int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+ u8 log_page, void *log, size_t size, size_t offset);
+
extern const struct attribute_group nvme_ns_id_attr_group;
extern const struct block_device_operations nvme_ns_head_ops;

diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index e878b95aeec4..9fe37f7e8185 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -81,10 +81,13 @@ struct nvm_rq;
struct nvm_id;
struct nvm_dev;
struct nvm_tgt_dev;
+struct nvm_chk_meta;

typedef int (nvm_id_fn)(struct nvm_dev *);
typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *);
typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int);
+typedef int (nvm_get_chk_meta_fn)(struct nvm_dev *, struct nvm_chk_meta *,
+ sector_t, int);
typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
typedef int (nvm_submit_io_sync_fn)(struct nvm_dev *, struct nvm_rq *);
typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
@@ -98,6 +101,8 @@ struct nvm_dev_ops {
nvm_op_bb_tbl_fn *get_bb_tbl;
nvm_op_set_bb_fn *set_bb_tbl;

+ nvm_get_chk_meta_fn *get_chk_meta;
+
nvm_submit_io_fn *submit_io;
nvm_submit_io_sync_fn *submit_io_sync;

@@ -227,6 +232,20 @@ struct nvm_addr_format {
u64 rsv_mask[2];
};

+/*
+ * Note: The structure size is linked to nvme_nvm_chk_meta such that the same
+ * buffer can be used when converting from little endian to cpu addressing.
+ */
+struct nvm_chk_meta {
+ u8 state;
+ u8 type;
+ u8 wi;
+ u8 rsvd[5];
+ u64 slba;
+ u64 cnlb;
+ u64 wp;
+};
+
struct nvm_target {
struct list_head list;
struct nvm_tgt_dev *dev;
@@ -496,6 +515,11 @@ extern struct nvm_dev *nvm_alloc_dev(int);
extern int nvm_register(struct nvm_dev *);
extern void nvm_unregister(struct nvm_dev *);

+
+extern int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev,
+ struct nvm_chk_meta *meta, struct ppa_addr ppa,
+ int nchks);
+
extern int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr *,
int, int);
extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *);
--
2.7.4


2018-02-28 17:11:27

by Javier González

[permalink] [raw]
Subject: [PATCH 10/15] lightnvm: pblk: check for supported version

At this point, only 1.2 spec is supported, thus check for it. Also,
since device-side L2P is only supported in the 1.2 spec, make sure to
only check its value under 1.2.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/pblk-init.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 11424beb214c..b67b5b11ae16 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -991,9 +991,15 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
struct pblk *pblk;
int ret;

- if (dev->geo.dom & NVM_RSP_L2P) {
+ if (geo->version != NVM_OCSSD_SPEC_12) {
+ pr_err("pblk: OCSSD version not supported (%u)\n",
+ geo->version);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (geo->version == NVM_OCSSD_SPEC_12 && geo->dom & NVM_RSP_L2P) {
pr_err("pblk: host-side L2P table not supported. (%x)\n",
- dev->geo.dom);
+ geo->dom);
return ERR_PTR(-EINVAL);
}

--
2.7.4


2018-02-28 17:11:29

by Javier González

[permalink] [raw]
Subject: [PATCH 12/15] lightnvn: pblk: use generic address format

Use the generic address format on common address manipulations.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/pblk-core.c | 10 +++++-----
drivers/lightnvm/pblk-map.c | 4 ++--
drivers/lightnvm/pblk-sysfs.c | 4 ++--
drivers/lightnvm/pblk.h | 4 ++--
4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 7d0bd33f11d9..2e10b18b61e3 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -885,7 +885,7 @@ int pblk_line_erase(struct pblk *pblk, struct pblk_line *line)
}

ppa = pblk->luns[bit].bppa; /* set ch and lun */
- ppa.g.blk = line->id;
+ ppa.a.blk = line->id;

atomic_dec(&line->left_eblks);
WARN_ON(test_and_set_bit(bit, line->erase_bitmap));
@@ -1686,8 +1686,8 @@ static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list,
int i;

for (i = 1; i < nr_ppas; i++)
- WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun ||
- ppa_list[0].g.ch != ppa_list[i].g.ch);
+ WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
+ ppa_list[0].a.ch != ppa_list[i].a.ch);
#endif

ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(30000));
@@ -1731,8 +1731,8 @@ void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas)
int i;

for (i = 1; i < nr_ppas; i++)
- WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun ||
- ppa_list[0].g.ch != ppa_list[i].g.ch);
+ WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
+ ppa_list[0].a.ch != ppa_list[i].a.ch);
#endif

rlun = &pblk->luns[pos];
diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c
index 04e08d76ea5f..20dbaa89c9df 100644
--- a/drivers/lightnvm/pblk-map.c
+++ b/drivers/lightnvm/pblk-map.c
@@ -127,7 +127,7 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
atomic_dec(&e_line->left_eblks);

*erase_ppa = rqd->ppa_list[i];
- erase_ppa->g.blk = e_line->id;
+ erase_ppa->a.blk = e_line->id;

spin_unlock(&e_line->lock);

@@ -168,6 +168,6 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
set_bit(bit, e_line->erase_bitmap);
atomic_dec(&e_line->left_eblks);
*erase_ppa = pblk->luns[bit].bppa; /* set ch and lun */
- erase_ppa->g.blk = e_line->id;
+ erase_ppa->a.blk = e_line->id;
}
}
diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
index cbb5b6edb7bf..a643dc623731 100644
--- a/drivers/lightnvm/pblk-sysfs.c
+++ b/drivers/lightnvm/pblk-sysfs.c
@@ -39,8 +39,8 @@ static ssize_t pblk_sysfs_luns_show(struct pblk *pblk, char *page)
sz += snprintf(page + sz, PAGE_SIZE - sz,
"pblk: pos:%d, ch:%d, lun:%d - %d\n",
i,
- rlun->bppa.g.ch,
- rlun->bppa.g.lun,
+ rlun->bppa.a.ch,
+ rlun->bppa.a.lun,
active);
}

diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index dd0089fe62b9..6ac64d9eb57e 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -936,12 +936,12 @@ static inline int pblk_pad_distance(struct pblk *pblk)

static inline int pblk_ppa_to_line(struct ppa_addr p)
{
- return p.g.blk;
+ return p.a.blk;
}

static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
{
- return p.g.lun * geo->num_ch + p.g.ch;
+ return p.a.lun * geo->num_ch + p.a.ch;
}

static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
--
2.7.4


2018-02-28 17:11:46

by Javier González

[permalink] [raw]
Subject: [PATCH 07/15] lightnvm: add support for 2.0 address format

Add support for 2.0 address format. Also, align address bits for 1.2 and
2.0 to be able to operate on channel and luns without requiring a format
conversion. Use a generic address format for this purpose.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/core.c | 20 ++++-----
include/linux/lightnvm.h | 105 ++++++++++++++++++++++++++++++++++-------------
2 files changed, 86 insertions(+), 39 deletions(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index b869e3051265..36d76de22dfc 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -194,8 +194,8 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,

for (j = 0; j < luns_in_chnl; j++) {
luns[lunid].ppa = 0;
- luns[lunid].g.ch = i;
- luns[lunid++].g.lun = j;
+ luns[lunid].a.ch = i;
+ luns[lunid++].a.lun = j;

lun_offs[j] = blun;
lun_roffs[j + blun] = blun;
@@ -556,22 +556,22 @@ static void nvm_unregister_map(struct nvm_dev *dev)
static void nvm_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p)
{
struct nvm_dev_map *dev_map = tgt_dev->map;
- struct nvm_ch_map *ch_map = &dev_map->chnls[p->g.ch];
- int lun_off = ch_map->lun_offs[p->g.lun];
+ struct nvm_ch_map *ch_map = &dev_map->chnls[p->a.ch];
+ int lun_off = ch_map->lun_offs[p->a.lun];

- p->g.ch += ch_map->ch_off;
- p->g.lun += lun_off;
+ p->a.ch += ch_map->ch_off;
+ p->a.lun += lun_off;
}

static void nvm_map_to_tgt(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p)
{
struct nvm_dev *dev = tgt_dev->parent;
struct nvm_dev_map *dev_rmap = dev->rmap;
- struct nvm_ch_map *ch_rmap = &dev_rmap->chnls[p->g.ch];
- int lun_roff = ch_rmap->lun_offs[p->g.lun];
+ struct nvm_ch_map *ch_rmap = &dev_rmap->chnls[p->a.ch];
+ int lun_roff = ch_rmap->lun_offs[p->a.lun];

- p->g.ch -= ch_rmap->ch_off;
- p->g.lun -= lun_roff;
+ p->a.ch -= ch_rmap->ch_off;
+ p->a.lun -= lun_roff;
}

static void nvm_ppa_tgt_to_dev(struct nvm_tgt_dev *tgt_dev,
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 4f88e3dc4d8c..73110adf27ad 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -16,12 +16,21 @@ enum {
NVM_IOTYPE_GC = 1,
};

-#define NVM_BLK_BITS (16)
-#define NVM_PG_BITS (16)
-#define NVM_SEC_BITS (8)
-#define NVM_PL_BITS (8)
-#define NVM_LUN_BITS (8)
-#define NVM_CH_BITS (7)
+/* common format */
+#define NVM_GEN_CH_BITS (8)
+#define NVM_GEN_LUN_BITS (8)
+#define NVM_GEN_BLK_BITS (16)
+#define NVM_GEN_RESERVED (32)
+
+/* 1.2 format */
+#define NVM_12_PG_BITS (16)
+#define NVM_12_PL_BITS (4)
+#define NVM_12_SEC_BITS (4)
+#define NVM_12_RESERVED (8)
+
+/* 2.0 format */
+#define NVM_20_SEC_BITS (24)
+#define NVM_20_RESERVED (8)

enum {
NVM_OCSSD_SPEC_12 = 12,
@@ -31,16 +40,34 @@ enum {
struct ppa_addr {
/* Generic structure for all addresses */
union {
+ /* generic device format */
struct {
- u64 blk : NVM_BLK_BITS;
- u64 pg : NVM_PG_BITS;
- u64 sec : NVM_SEC_BITS;
- u64 pl : NVM_PL_BITS;
- u64 lun : NVM_LUN_BITS;
- u64 ch : NVM_CH_BITS;
- u64 reserved : 1;
+ u64 ch : NVM_GEN_CH_BITS;
+ u64 lun : NVM_GEN_LUN_BITS;
+ u64 blk : NVM_GEN_BLK_BITS;
+ u64 reserved : NVM_GEN_RESERVED;
+ } a;
+
+ /* 1.2 device format */
+ struct {
+ u64 ch : NVM_GEN_CH_BITS;
+ u64 lun : NVM_GEN_LUN_BITS;
+ u64 blk : NVM_GEN_BLK_BITS;
+ u64 pg : NVM_12_PG_BITS;
+ u64 pl : NVM_12_PL_BITS;
+ u64 sec : NVM_12_SEC_BITS;
+ u64 reserved : NVM_12_RESERVED;
} g;

+ /* 2.0 device format */
+ struct {
+ u64 grp : NVM_GEN_CH_BITS;
+ u64 pu : NVM_GEN_LUN_BITS;
+ u64 chk : NVM_GEN_BLK_BITS;
+ u64 sec : NVM_20_SEC_BITS;
+ u64 reserved : NVM_20_RESERVED;
+ } m;
+
struct {
u64 line : 63;
u64 is_cached : 1;
@@ -376,16 +403,26 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
struct ppa_addr r)
{
struct nvm_geo *geo = &tgt_dev->geo;
- struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&geo->addrf;
struct ppa_addr l;

- l.ppa = ((u64)r.g.ch) << ppaf->ch_offset;
- l.ppa |= ((u64)r.g.lun) << ppaf->lun_offset;
- l.ppa |= ((u64)r.g.blk) << ppaf->blk_offset;
- l.ppa |= ((u64)r.g.pg) << ppaf->pg_offset;
- l.ppa |= ((u64)r.g.pl) << ppaf->pln_offset;
- l.ppa |= ((u64)r.g.sec) << ppaf->sec_offset;
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&geo->addrf;
+
+ l.ppa = ((u64)r.g.ch) << ppaf->ch_offset;
+ l.ppa |= ((u64)r.g.lun) << ppaf->lun_offset;
+ l.ppa |= ((u64)r.g.blk) << ppaf->blk_offset;
+ l.ppa |= ((u64)r.g.pg) << ppaf->pg_offset;
+ l.ppa |= ((u64)r.g.pl) << ppaf->pln_offset;
+ l.ppa |= ((u64)r.g.sec) << ppaf->sec_offset;
+ } else {
+ struct nvm_addr_format *lbaf = &geo->addrf;
+
+ l.ppa = ((u64)r.m.grp) << lbaf->ch_offset;
+ l.ppa |= ((u64)r.m.pu) << lbaf->lun_offset;
+ l.ppa |= ((u64)r.m.chk) << lbaf->chk_offset;
+ l.ppa |= ((u64)r.m.sec) << lbaf->sec_offset;
+ }

return l;
}
@@ -394,18 +431,28 @@ static inline struct ppa_addr dev_to_generic_addr(struct nvm_tgt_dev *tgt_dev,
struct ppa_addr r)
{
struct nvm_geo *geo = &tgt_dev->geo;
- struct nvm_addr_format_12 *ppaf =
- (struct nvm_addr_format_12 *)&geo->addrf;
struct ppa_addr l;

l.ppa = 0;

- l.g.ch = (r.ppa & ppaf->ch_mask) >> ppaf->ch_offset;
- l.g.lun = (r.ppa & ppaf->lun_mask) >> ppaf->lun_offset;
- l.g.blk = (r.ppa & ppaf->blk_mask) >> ppaf->blk_offset;
- l.g.pg = (r.ppa & ppaf->pg_mask) >> ppaf->pg_offset;
- l.g.pl = (r.ppa & ppaf->pln_mask) >> ppaf->pln_offset;
- l.g.sec = (r.ppa & ppaf->sec_mask) >> ppaf->sec_offset;
+ if (geo->version == NVM_OCSSD_SPEC_12) {
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&geo->addrf;
+
+ l.g.ch = (r.ppa & ppaf->ch_mask) >> ppaf->ch_offset;
+ l.g.lun = (r.ppa & ppaf->lun_mask) >> ppaf->lun_offset;
+ l.g.blk = (r.ppa & ppaf->blk_mask) >> ppaf->blk_offset;
+ l.g.pg = (r.ppa & ppaf->pg_mask) >> ppaf->pg_offset;
+ l.g.pl = (r.ppa & ppaf->pln_mask) >> ppaf->pln_offset;
+ l.g.sec = (r.ppa & ppaf->sec_mask) >> ppaf->sec_offset;
+ } else {
+ struct nvm_addr_format *lbaf = &geo->addrf;
+
+ l.m.grp = (r.ppa & lbaf->ch_mask) >> lbaf->ch_offset;
+ l.m.pu = (r.ppa & lbaf->lun_mask) >> lbaf->lun_offset;
+ l.m.chk = (r.ppa & lbaf->chk_mask) >> lbaf->chk_offset;
+ l.m.sec = (r.ppa & lbaf->sec_mask) >> lbaf->sec_offset;
+ }

return l;
}
--
2.7.4


2018-02-28 17:11:57

by Javier González

[permalink] [raw]
Subject: [PATCH 08/15] lightnvm: make address conversions depend on generic device

On address conversions, use the generic device, instead of the target
device. This allows to use conversions outside of the target's realm.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/core.c | 4 ++--
include/linux/lightnvm.h | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 36d76de22dfc..ed33e0b11788 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -581,7 +581,7 @@ static void nvm_ppa_tgt_to_dev(struct nvm_tgt_dev *tgt_dev,

for (i = 0; i < nr_ppas; i++) {
nvm_map_to_dev(tgt_dev, &ppa_list[i]);
- ppa_list[i] = generic_to_dev_addr(tgt_dev, ppa_list[i]);
+ ppa_list[i] = generic_to_dev_addr(tgt_dev->parent, ppa_list[i]);
}
}

@@ -591,7 +591,7 @@ static void nvm_ppa_dev_to_tgt(struct nvm_tgt_dev *tgt_dev,
int i;

for (i = 0; i < nr_ppas; i++) {
- ppa_list[i] = dev_to_generic_addr(tgt_dev, ppa_list[i]);
+ ppa_list[i] = dev_to_generic_addr(tgt_dev->parent, ppa_list[i]);
nvm_map_to_tgt(tgt_dev, &ppa_list[i]);
}
}
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 73110adf27ad..e878b95aeec4 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -399,10 +399,10 @@ struct nvm_dev {
struct list_head targets;
};

-static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
+static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
struct ppa_addr r)
{
- struct nvm_geo *geo = &tgt_dev->geo;
+ struct nvm_geo *geo = &dev->geo;
struct ppa_addr l;

if (geo->version == NVM_OCSSD_SPEC_12) {
@@ -427,10 +427,10 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
return l;
}

-static inline struct ppa_addr dev_to_generic_addr(struct nvm_tgt_dev *tgt_dev,
+static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev,
struct ppa_addr r)
{
- struct nvm_geo *geo = &tgt_dev->geo;
+ struct nvm_geo *geo = &dev->geo;
struct ppa_addr l;

l.ppa = 0;
--
2.7.4


2018-02-28 17:13:18

by Javier González

[permalink] [raw]
Subject: [PATCH 05/15] lightnvm: complete geo structure with maxoc*

Complete the generic geometry structure with the maxoc and maxocpu
felds, present in the 2.0 spec. Also, expose them through sysfs.

Signed-off-by: Javier González <[email protected]>
---
drivers/nvme/host/lightnvm.c | 17 +++++++++++++++++
include/linux/lightnvm.h | 2 ++
2 files changed, 19 insertions(+)

diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 85f336a79cda..afb5f883f8c8 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -323,6 +323,13 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
geo->ws_opt = sec_per_pg;
geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */

+ /* Do not impose values for maximum number of open blocks as it is
+ * unspecified in 1.2. Users of 1.2 must be aware of this and eventually
+ * specify these values through a quirk if restrictions apply.
+ */
+ geo->maxoc = geo->all_luns * geo->nr_chks;
+ geo->maxocpu = geo->nr_chks;
+
geo->cap = le32_to_cpu(src->mccap);

geo->trdt = le32_to_cpu(src->trdt);
@@ -410,6 +417,8 @@ static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
geo->ws_min = le32_to_cpu(id->ws_min);
geo->ws_opt = le32_to_cpu(id->ws_opt);
geo->mw_cunits = le32_to_cpu(id->mw_cunits);
+ geo->maxoc = le32_to_cpu(id->maxoc);
+ geo->maxocpu = le32_to_cpu(id->maxocpu);

geo->cap = le32_to_cpu(id->mccap);

@@ -1054,6 +1063,10 @@ static ssize_t nvm_dev_attr_show_20(struct device *dev,
return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_min);
} else if (strcmp(attr->name, "ws_opt") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_opt);
+ } else if (strcmp(attr->name, "maxoc") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->maxoc);
+ } else if (strcmp(attr->name, "maxocpu") == 0) {
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->maxocpu);
} else if (strcmp(attr->name, "mw_cunits") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", geo->mw_cunits);
} else if (strcmp(attr->name, "write_typ") == 0) {
@@ -1151,6 +1164,8 @@ static NVM_DEV_ATTR_20_RO(chunks);
static NVM_DEV_ATTR_20_RO(clba);
static NVM_DEV_ATTR_20_RO(ws_min);
static NVM_DEV_ATTR_20_RO(ws_opt);
+static NVM_DEV_ATTR_20_RO(maxoc);
+static NVM_DEV_ATTR_20_RO(maxocpu);
static NVM_DEV_ATTR_20_RO(mw_cunits);
static NVM_DEV_ATTR_20_RO(write_typ);
static NVM_DEV_ATTR_20_RO(write_max);
@@ -1167,6 +1182,8 @@ static struct attribute *nvm_dev_attrs_20[] = {
&dev_attr_clba.attr,
&dev_attr_ws_min.attr,
&dev_attr_ws_opt.attr,
+ &dev_attr_maxoc.attr,
+ &dev_attr_maxocpu.attr,
&dev_attr_mw_cunits.attr,

&dev_attr_read_typ.attr,
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index b8bc158a2472..2102b092c7eb 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -296,6 +296,8 @@ struct nvm_geo {
u32 ws_min; /* minimum write size */
u32 ws_opt; /* optimal write size */
u32 mw_cunits; /* distance required for successful read */
+ u32 maxoc; /* maximum open chunks */
+ u32 maxocpu; /* maximum open chunks per parallel unit */

/* device capabilities. Note that this represents capabilities in 1.2
* and media and controller capabilities in 2.0
--
2.7.4


2018-02-28 17:14:04

by Javier González

[permalink] [raw]
Subject: [PATCH 06/15] lightnvm: normalize geometry nomenclature

Normalize nomenclature for naming channels, luns, chunks, planes and
sectors as well as derivations in order to improve readability.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/core.c | 89 +++++++++++++++++++++----------------------
drivers/lightnvm/pblk-core.c | 4 +-
drivers/lightnvm/pblk-init.c | 30 +++++++--------
drivers/lightnvm/pblk-sysfs.c | 4 +-
drivers/lightnvm/pblk.h | 20 +++++-----
drivers/nvme/host/lightnvm.c | 54 +++++++++++++-------------
include/linux/lightnvm.h | 16 ++++----
7 files changed, 108 insertions(+), 109 deletions(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index c4f72fbad2bf..b869e3051265 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -36,13 +36,13 @@ static DECLARE_RWSEM(nvm_lock);
/* Map between virtual and physical channel and lun */
struct nvm_ch_map {
int ch_off;
- int nr_luns;
+ int num_lun;
int *lun_offs;
};

struct nvm_dev_map {
struct nvm_ch_map *chnls;
- int nr_chnls;
+ int num_ch;
};

static struct nvm_target *nvm_find_target(struct nvm_dev *dev, const char *name)
@@ -114,15 +114,15 @@ static void nvm_remove_tgt_dev(struct nvm_tgt_dev *tgt_dev, int clear)
struct nvm_dev_map *dev_map = tgt_dev->map;
int i, j;

- for (i = 0; i < dev_map->nr_chnls; i++) {
+ for (i = 0; i < dev_map->num_ch; i++) {
struct nvm_ch_map *ch_map = &dev_map->chnls[i];
int *lun_offs = ch_map->lun_offs;
int ch = i + ch_map->ch_off;

if (clear) {
- for (j = 0; j < ch_map->nr_luns; j++) {
+ for (j = 0; j < ch_map->num_lun; j++) {
int lun = j + lun_offs[j];
- int lunid = (ch * dev->geo.nr_luns) + lun;
+ int lunid = (ch * dev->geo.num_lun) + lun;

WARN_ON(!test_and_clear_bit(lunid,
dev->lun_map));
@@ -147,47 +147,46 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
struct nvm_dev_map *dev_rmap = dev->rmap;
struct nvm_dev_map *dev_map;
struct ppa_addr *luns;
- int nr_luns = lun_end - lun_begin + 1;
- int luns_left = nr_luns;
- int nr_chnls = nr_luns / dev->geo.nr_luns;
- int nr_chnls_mod = nr_luns % dev->geo.nr_luns;
- int bch = lun_begin / dev->geo.nr_luns;
- int blun = lun_begin % dev->geo.nr_luns;
+ int num_lun = lun_end - lun_begin + 1;
+ int luns_left = num_lun;
+ int num_ch = num_lun / dev->geo.num_lun;
+ int num_ch_mod = num_lun % dev->geo.num_lun;
+ int bch = lun_begin / dev->geo.num_lun;
+ int blun = lun_begin % dev->geo.num_lun;
int lunid = 0;
int lun_balanced = 1;
- int sec_per_lun, prev_nr_luns;
+ int sec_per_lun, prev_num_lun;
int i, j;

- nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1;
+ num_ch = (num_ch_mod == 0) ? num_ch : num_ch + 1;

dev_map = kmalloc(sizeof(struct nvm_dev_map), GFP_KERNEL);
if (!dev_map)
goto err_dev;

- dev_map->chnls = kcalloc(nr_chnls, sizeof(struct nvm_ch_map),
- GFP_KERNEL);
+ dev_map->chnls = kcalloc(num_ch, sizeof(struct nvm_ch_map), GFP_KERNEL);
if (!dev_map->chnls)
goto err_chnls;

- luns = kcalloc(nr_luns, sizeof(struct ppa_addr), GFP_KERNEL);
+ luns = kcalloc(num_lun, sizeof(struct ppa_addr), GFP_KERNEL);
if (!luns)
goto err_luns;

- prev_nr_luns = (luns_left > dev->geo.nr_luns) ?
- dev->geo.nr_luns : luns_left;
- for (i = 0; i < nr_chnls; i++) {
+ prev_num_lun = (luns_left > dev->geo.num_lun) ?
+ dev->geo.num_lun : luns_left;
+ for (i = 0; i < num_ch; i++) {
struct nvm_ch_map *ch_rmap = &dev_rmap->chnls[i + bch];
int *lun_roffs = ch_rmap->lun_offs;
struct nvm_ch_map *ch_map = &dev_map->chnls[i];
int *lun_offs;
- int luns_in_chnl = (luns_left > dev->geo.nr_luns) ?
- dev->geo.nr_luns : luns_left;
+ int luns_in_chnl = (luns_left > dev->geo.num_lun) ?
+ dev->geo.num_lun : luns_left;

- if (lun_balanced && prev_nr_luns != luns_in_chnl)
+ if (lun_balanced && prev_num_lun != luns_in_chnl)
lun_balanced = 0;

ch_map->ch_off = ch_rmap->ch_off = bch;
- ch_map->nr_luns = luns_in_chnl;
+ ch_map->num_lun = luns_in_chnl;

lun_offs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL);
if (!lun_offs)
@@ -209,7 +208,7 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
luns_left -= luns_in_chnl;
}

- dev_map->nr_chnls = nr_chnls;
+ dev_map->num_ch = num_ch;

tgt_dev = kmalloc(sizeof(struct nvm_tgt_dev), GFP_KERNEL);
if (!tgt_dev)
@@ -219,15 +218,15 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo));

/* Target device only owns a portion of the physical device */
- tgt_dev->geo.nr_chnls = nr_chnls;
- tgt_dev->geo.nr_luns = (lun_balanced) ? prev_nr_luns : -1;
- tgt_dev->geo.all_luns = nr_luns;
- tgt_dev->geo.all_chunks = nr_luns * dev->geo.nr_chks;
+ tgt_dev->geo.num_ch = num_ch;
+ tgt_dev->geo.num_lun = (lun_balanced) ? prev_num_lun : -1;
+ tgt_dev->geo.all_luns = num_lun;
+ tgt_dev->geo.all_chunks = num_lun * dev->geo.num_chk;

tgt_dev->geo.op = op;

- sec_per_lun = dev->geo.clba * dev->geo.nr_chks;
- tgt_dev->geo.total_secs = nr_luns * sec_per_lun;
+ sec_per_lun = dev->geo.clba * dev->geo.num_chk;
+ tgt_dev->geo.total_secs = num_lun * sec_per_lun;

tgt_dev->q = dev->q;
tgt_dev->map = dev_map;
@@ -505,20 +504,20 @@ static int nvm_register_map(struct nvm_dev *dev)
if (!rmap)
goto err_rmap;

- rmap->chnls = kcalloc(dev->geo.nr_chnls, sizeof(struct nvm_ch_map),
+ rmap->chnls = kcalloc(dev->geo.num_ch, sizeof(struct nvm_ch_map),
GFP_KERNEL);
if (!rmap->chnls)
goto err_chnls;

- for (i = 0; i < dev->geo.nr_chnls; i++) {
+ for (i = 0; i < dev->geo.num_ch; i++) {
struct nvm_ch_map *ch_rmap;
int *lun_roffs;
- int luns_in_chnl = dev->geo.nr_luns;
+ int luns_in_chnl = dev->geo.num_lun;

ch_rmap = &rmap->chnls[i];

ch_rmap->ch_off = -1;
- ch_rmap->nr_luns = luns_in_chnl;
+ ch_rmap->num_lun = luns_in_chnl;

lun_roffs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL);
if (!lun_roffs)
@@ -547,7 +546,7 @@ static void nvm_unregister_map(struct nvm_dev *dev)
struct nvm_dev_map *rmap = dev->rmap;
int i;

- for (i = 0; i < dev->geo.nr_chnls; i++)
+ for (i = 0; i < dev->geo.num_ch; i++)
kfree(rmap->chnls[i].lun_offs);

kfree(rmap->chnls);
@@ -676,7 +675,7 @@ static int nvm_set_rqd_ppalist(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd,
int i, plane_cnt, pl_idx;
struct ppa_addr ppa;

- if (geo->plane_mode == NVM_PLANE_SINGLE && nr_ppas == 1) {
+ if (geo->pln_mode == NVM_PLANE_SINGLE && nr_ppas == 1) {
rqd->nr_ppas = nr_ppas;
rqd->ppa_addr = ppas[0];

@@ -690,7 +689,7 @@ static int nvm_set_rqd_ppalist(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd,
return -ENOMEM;
}

- plane_cnt = geo->plane_mode;
+ plane_cnt = geo->pln_mode;
rqd->nr_ppas *= plane_cnt;

for (i = 0; i < nr_ppas; i++) {
@@ -808,15 +807,15 @@ int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks)
struct nvm_geo *geo = &dev->geo;
int blk, offset, pl, blktype;

- if (nr_blks != geo->nr_chks * geo->plane_mode)
+ if (nr_blks != geo->num_chk * geo->pln_mode)
return -EINVAL;

- for (blk = 0; blk < geo->nr_chks; blk++) {
- offset = blk * geo->plane_mode;
+ for (blk = 0; blk < geo->num_chk; blk++) {
+ offset = blk * geo->pln_mode;
blktype = blks[offset];

/* Bad blocks on any planes take precedence over other types */
- for (pl = 0; pl < geo->plane_mode; pl++) {
+ for (pl = 0; pl < geo->pln_mode; pl++) {
if (blks[offset + pl] &
(NVM_BLK_T_BAD|NVM_BLK_T_GRWN_BAD)) {
blktype = blks[offset + pl];
@@ -827,7 +826,7 @@ int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks)
blks[blk] = blktype;
}

- return geo->nr_chks;
+ return geo->num_chk;
}
EXPORT_SYMBOL(nvm_bb_tbl_fold);

@@ -901,9 +900,9 @@ static int nvm_init(struct nvm_dev *dev)
}

pr_info("nvm: registered %s [%u/%u/%u/%u/%u]\n",
- dev->name, geo->ws_min, geo->ws_opt,
- geo->nr_chks, geo->all_luns,
- geo->nr_chnls);
+ dev->name, dev->geo.ws_min, dev->geo.ws_opt,
+ dev->geo.num_chk, dev->geo.all_luns,
+ dev->geo.num_ch);
return 0;
err:
pr_err("nvm: failed to initialize nvm\n");
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 169589ddd457..7d0bd33f11d9 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -1745,10 +1745,10 @@ void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas,
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
struct pblk_lun *rlun;
- int nr_luns = geo->all_luns;
+ int num_lun = geo->all_luns;
int bit = -1;

- while ((bit = find_next_bit(lun_bitmap, nr_luns, bit + 1)) < nr_luns) {
+ while ((bit = find_next_bit(lun_bitmap, num_lun, bit + 1)) < num_lun) {
rlun = &pblk->luns[bit];
up(&rlun->wr_sem);
}
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 9b5ee05c3028..11424beb214c 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -162,15 +162,15 @@ static int pblk_set_addrf_12(struct nvm_geo *geo,
int power_len;

/* Re-calculate channel and lun format to adapt to configuration */
- power_len = get_count_order(geo->nr_chnls);
- if (1 << power_len != geo->nr_chnls) {
+ power_len = get_count_order(geo->num_ch);
+ if (1 << power_len != geo->num_ch) {
pr_err("pblk: supports only power-of-two channel config.\n");
return -EINVAL;
}
dst->ch_len = power_len;

- power_len = get_count_order(geo->nr_luns);
- if (1 << power_len != geo->nr_luns) {
+ power_len = get_count_order(geo->num_lun);
+ if (1 << power_len != geo->num_lun) {
pr_err("pblk: supports only power-of-two LUN config.\n");
return -EINVAL;
}
@@ -179,16 +179,16 @@ static int pblk_set_addrf_12(struct nvm_geo *geo,
dst->blk_len = src->blk_len;
dst->pg_len = src->pg_len;
dst->pln_len = src->pln_len;
- dst->sect_len = src->sect_len;
+ dst->sec_len = src->sec_len;

- dst->sect_offset = 0;
- dst->pln_offset = dst->sect_len;
+ dst->sec_offset = 0;
+ dst->pln_offset = dst->sec_len;
dst->ch_offset = dst->pln_offset + dst->pln_len;
dst->lun_offset = dst->ch_offset + dst->ch_len;
dst->pg_offset = dst->lun_offset + dst->lun_len;
dst->blk_offset = dst->pg_offset + dst->pg_len;

- dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
+ dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset;
dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
@@ -448,7 +448,7 @@ static void *pblk_bb_get_log(struct pblk *pblk)
int i, nr_blks, blk_per_lun;
int ret;

- blk_per_lun = geo->nr_chks * geo->plane_mode;
+ blk_per_lun = geo->num_chk * geo->pln_mode;
nr_blks = blk_per_lun * geo->all_luns;

log = kmalloc(nr_blks, GFP_KERNEL);
@@ -475,7 +475,7 @@ static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line,
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
int i, bb_cnt = 0;
- int blk_per_lun = geo->nr_chks * geo->plane_mode;
+ int blk_per_lun = geo->num_chk * geo->pln_mode;

for (i = 0; i < blk_per_line; i++) {
struct pblk_lun *rlun = &pblk->luns[i];
@@ -499,7 +499,7 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
int i;

/* TODO: Implement unbalanced LUN support */
- if (geo->nr_luns < 0) {
+ if (geo->num_lun < 0) {
pr_err("pblk: unbalanced LUN config.\n");
return -EINVAL;
}
@@ -511,9 +511,9 @@ static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)

for (i = 0; i < geo->all_luns; i++) {
/* Stripe across channels */
- int ch = i % geo->nr_chnls;
- int lun_raw = i / geo->nr_chnls;
- int lunid = lun_raw + ch * geo->nr_luns;
+ int ch = i % geo->num_ch;
+ int lun_raw = i / geo->num_ch;
+ int lunid = lun_raw + ch * geo->num_lun;

rlun = &pblk->luns[i];
rlun->bppa = luns[lunid];
@@ -740,7 +740,7 @@ static int pblk_lines_init(struct pblk *pblk)
return -EINVAL;
}

- l_mg->nr_lines = geo->nr_chks;
+ l_mg->nr_lines = geo->num_chk;
l_mg->log_line = l_mg->data_line = NULL;
l_mg->l_seq_nr = l_mg->d_seq_nr = 0;
l_mg->nr_free_lines = 0;
diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
index 33199c6af267..462a787893d5 100644
--- a/drivers/lightnvm/pblk-sysfs.c
+++ b/drivers/lightnvm/pblk-sysfs.c
@@ -128,7 +128,7 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
ppaf->blk_offset, ppaf->blk_len,
ppaf->pg_offset, ppaf->pg_len,
ppaf->pln_offset, ppaf->pln_len,
- ppaf->sect_offset, ppaf->sect_len);
+ ppaf->sec_offset, ppaf->sec_len);

sz += snprintf(page + sz, PAGE_SIZE - sz,
"device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
@@ -137,7 +137,7 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
geo_ppaf->blk_offset, geo_ppaf->blk_len,
geo_ppaf->pg_offset, geo_ppaf->pg_len,
geo_ppaf->pln_offset, geo_ppaf->pln_len,
- geo_ppaf->sect_offset, geo_ppaf->sect_len);
+ geo_ppaf->sec_offset, geo_ppaf->sec_len);

return sz;
}
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index b29c1e6698aa..bae2cc758de8 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -941,7 +941,7 @@ static inline int pblk_ppa_to_line(struct ppa_addr p)

static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
{
- return p.g.lun * geo->nr_chnls + p.g.ch;
+ return p.g.lun * geo->num_ch + p.g.ch;
}

static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
@@ -957,7 +957,7 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
- ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sect_offset;
+ ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sec_offset;

return ppa;
}
@@ -973,7 +973,7 @@ static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
paddr |= (u64)p.g.lun << ppaf->lun_offset;
paddr |= (u64)p.g.pg << ppaf->pg_offset;
paddr |= (u64)p.g.pl << ppaf->pln_offset;
- paddr |= (u64)p.g.sec << ppaf->sect_offset;
+ paddr |= (u64)p.g.sec << ppaf->sec_offset;

return paddr;
}
@@ -998,7 +998,7 @@ static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
ppa64.g.blk = (ppa32 & ppaf->blk_mask) >> ppaf->blk_offset;
ppa64.g.pg = (ppa32 & ppaf->pg_mask) >> ppaf->pg_offset;
ppa64.g.pl = (ppa32 & ppaf->pln_mask) >> ppaf->pln_offset;
- ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> ppaf->sect_offset;
+ ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> ppaf->sec_offset;
}

return ppa64;
@@ -1022,7 +1022,7 @@ static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
ppa32 |= ppa64.g.blk << ppaf->blk_offset;
ppa32 |= ppa64.g.pg << ppaf->pg_offset;
ppa32 |= ppa64.g.pl << ppaf->pln_offset;
- ppa32 |= ppa64.g.sec << ppaf->sect_offset;
+ ppa32 |= ppa64.g.sec << ppaf->sec_offset;
}

return ppa32;
@@ -1140,7 +1140,7 @@ static inline int pblk_set_progr_mode(struct pblk *pblk, int type)
struct nvm_geo *geo = &dev->geo;
int flags;

- flags = geo->plane_mode >> 1;
+ flags = geo->pln_mode >> 1;

if (type == PBLK_WRITE)
flags |= NVM_IO_SCRAMBLE_ENABLE;
@@ -1161,7 +1161,7 @@ static inline int pblk_set_read_mode(struct pblk *pblk, int type)

flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
if (type == PBLK_READ_SEQUENTIAL)
- flags |= geo->plane_mode >> 1;
+ flags |= geo->pln_mode >> 1;

return flags;
}
@@ -1214,10 +1214,10 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev,
ppa = &ppas[i];

if (!ppa->c.is_cached &&
- ppa->g.ch < geo->nr_chnls &&
- ppa->g.lun < geo->nr_luns &&
+ ppa->g.ch < geo->num_ch &&
+ ppa->g.lun < geo->num_lun &&
ppa->g.pl < geo->num_pln &&
- ppa->g.blk < geo->nr_chks &&
+ ppa->g.blk < geo->num_chk &&
ppa->g.pg < geo->num_pg &&
ppa->g.sec < geo->ws_min)
continue;
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index afb5f883f8c8..f7135659f918 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -262,21 +262,21 @@ static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
dst->blk_len = src->blk_len;
dst->pg_len = src->pg_len;
dst->pln_len = src->pln_len;
- dst->sect_len = src->sec_len;
+ dst->sec_len = src->sec_len;

dst->ch_offset = src->ch_offset;
dst->lun_offset = src->lun_offset;
dst->blk_offset = src->blk_offset;
dst->pg_offset = src->pg_offset;
dst->pln_offset = src->pln_offset;
- dst->sect_offset = src->sec_offset;
+ dst->sec_offset = src->sec_offset;

dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
- dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
+ dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset;
}

static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
@@ -302,11 +302,11 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
/* Set compacted version for upper layers */
geo->version = NVM_OCSSD_SPEC_12;

- geo->nr_chnls = src->num_ch;
- geo->nr_luns = src->num_lun;
- geo->all_luns = geo->nr_chnls * geo->nr_luns;
+ geo->num_ch = src->num_ch;
+ geo->num_lun = src->num_lun;
+ geo->all_luns = geo->num_ch * geo->num_lun;

- geo->nr_chks = le16_to_cpu(src->num_chk);
+ geo->num_chk = le16_to_cpu(src->num_chk);

geo->csecs = le16_to_cpu(src->csecs);
geo->sos = le16_to_cpu(src->sos);
@@ -316,7 +316,7 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
sec_per_pl = sec_per_pg * src->num_pln;
geo->clba = sec_per_pl * pg_per_blk;

- geo->all_chunks = geo->all_luns * geo->nr_chks;
+ geo->all_chunks = geo->all_luns * geo->num_chk;
geo->total_secs = geo->clba * geo->all_chunks;

geo->ws_min = sec_per_pg;
@@ -327,8 +327,8 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
* unspecified in 1.2. Users of 1.2 must be aware of this and eventually
* specify these values through a quirk if restrictions apply.
*/
- geo->maxoc = geo->all_luns * geo->nr_chks;
- geo->maxocpu = geo->nr_chks;
+ geo->maxoc = geo->all_luns * geo->num_chk;
+ geo->maxocpu = geo->num_chk;

geo->cap = le32_to_cpu(src->mccap);

@@ -350,13 +350,13 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
geo->cpar = le16_to_cpu(src->cpar);
geo->mpos = le32_to_cpu(src->mpos);

- geo->plane_mode = NVM_PLANE_SINGLE;
+ geo->pln_mode = NVM_PLANE_SINGLE;

if (geo->mpos & 0x020202) {
- geo->plane_mode = NVM_PLANE_DOUBLE;
+ geo->pln_mode = NVM_PLANE_DOUBLE;
geo->ws_opt <<= 1;
} else if (geo->mpos & 0x040404) {
- geo->plane_mode = NVM_PLANE_QUAD;
+ geo->pln_mode = NVM_PLANE_QUAD;
geo->ws_opt <<= 2;
}

@@ -404,14 +404,14 @@ static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
return -EINVAL;
}

- geo->nr_chnls = le16_to_cpu(id->num_grp);
- geo->nr_luns = le16_to_cpu(id->num_pu);
- geo->all_luns = geo->nr_chnls * geo->nr_luns;
+ geo->num_ch = le16_to_cpu(id->num_grp);
+ geo->num_lun = le16_to_cpu(id->num_pu);
+ geo->all_luns = geo->num_ch * geo->num_lun;

- geo->nr_chks = le32_to_cpu(id->num_chk);
+ geo->num_chk = le32_to_cpu(id->num_chk);
geo->clba = le32_to_cpu(id->clba);

- geo->all_chunks = geo->all_luns * geo->nr_chks;
+ geo->all_chunks = geo->all_luns * geo->num_chk;
geo->total_secs = geo->clba * geo->all_chunks;

geo->ws_min = le32_to_cpu(id->ws_min);
@@ -487,7 +487,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
struct nvme_ctrl *ctrl = ns->ctrl;
struct nvme_nvm_command c = {};
struct nvme_nvm_bb_tbl *bb_tbl;
- int nr_blks = geo->nr_chks * geo->num_pln;
+ int nr_blks = geo->num_chk * geo->num_pln;
int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blks;
int ret = 0;

@@ -528,7 +528,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
goto out;
}

- memcpy(blks, bb_tbl->blk, geo->nr_chks * geo->num_pln);
+ memcpy(blks, bb_tbl->blk, geo->num_chk * geo->num_pln);
out:
kfree(bb_tbl);
return ret;
@@ -972,7 +972,7 @@ static ssize_t nvm_dev_attr_show_ppaf(struct nvm_addr_format_12 *ppaf,
ppaf->pln_offset, ppaf->pln_len,
ppaf->blk_offset, ppaf->blk_len,
ppaf->pg_offset, ppaf->pg_len,
- ppaf->sect_offset, ppaf->sect_len);
+ ppaf->sec_offset, ppaf->sec_len);
}

static ssize_t nvm_dev_attr_show_12(struct device *dev,
@@ -1002,13 +1002,13 @@ static ssize_t nvm_dev_attr_show_12(struct device *dev,
} else if (strcmp(attr->name, "flash_media_type") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", geo->fmtype);
} else if (strcmp(attr->name, "num_channels") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_ch);
} else if (strcmp(attr->name, "num_luns") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_lun);
} else if (strcmp(attr->name, "num_planes") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pln);
} else if (strcmp(attr->name, "num_blocks") == 0) { /* u16 */
- return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_chk);
} else if (strcmp(attr->name, "num_pages") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pg);
} else if (strcmp(attr->name, "page_size") == 0) {
@@ -1052,11 +1052,11 @@ static ssize_t nvm_dev_attr_show_20(struct device *dev,
attr = &dattr->attr;

if (strcmp(attr->name, "groups") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_ch);
} else if (strcmp(attr->name, "punits") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_lun);
} else if (strcmp(attr->name, "chunks") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_chk);
} else if (strcmp(attr->name, "clba") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", geo->clba);
} else if (strcmp(attr->name, "ws_min") == 0) {
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 2102b092c7eb..4f88e3dc4d8c 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -163,14 +163,14 @@ struct nvm_addr_format_12 {
u8 blk_len;
u8 pg_len;
u8 pln_len;
- u8 sect_len;
+ u8 sec_len;

u8 ch_offset;
u8 lun_offset;
u8 blk_offset;
u8 pg_offset;
u8 pln_offset;
- u8 sect_offset;
+ u8 sec_offset;

u64 ch_mask;
u64 lun_mask;
@@ -275,8 +275,8 @@ struct nvm_geo {
u8 version;

/* instance specific geometry */
- int nr_chnls;
- int nr_luns; /* per channel */
+ int num_ch;
+ int num_lun; /* per channel */

/* calculated values */
int all_luns; /* across channels */
@@ -287,7 +287,7 @@ struct nvm_geo {
sector_t total_secs; /* across channels */

/* chunk geometry */
- u32 nr_chks; /* chunks per lun */
+ u32 num_chk; /* chunks per lun */
u32 clba; /* sectors per chunk */
u16 csecs; /* sector size */
u16 sos; /* out-of-band area size */
@@ -327,7 +327,7 @@ struct nvm_geo {
u32 mpos;

u8 num_pln;
- u8 plane_mode;
+ u8 pln_mode;
u16 num_pg;
u16 fpg_sz;
};
@@ -385,7 +385,7 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
l.ppa |= ((u64)r.g.blk) << ppaf->blk_offset;
l.ppa |= ((u64)r.g.pg) << ppaf->pg_offset;
l.ppa |= ((u64)r.g.pl) << ppaf->pln_offset;
- l.ppa |= ((u64)r.g.sec) << ppaf->sect_offset;
+ l.ppa |= ((u64)r.g.sec) << ppaf->sec_offset;

return l;
}
@@ -405,7 +405,7 @@ static inline struct ppa_addr dev_to_generic_addr(struct nvm_tgt_dev *tgt_dev,
l.g.blk = (r.ppa & ppaf->blk_mask) >> ppaf->blk_offset;
l.g.pg = (r.ppa & ppaf->pg_mask) >> ppaf->pg_offset;
l.g.pl = (r.ppa & ppaf->pln_mask) >> ppaf->pln_offset;
- l.g.sec = (r.ppa & ppaf->sec_mask) >> ppaf->sect_offset;
+ l.g.sec = (r.ppa & ppaf->sec_mask) >> ppaf->sec_offset;

return l;
}
--
2.7.4


2018-02-28 17:14:12

by Javier González

[permalink] [raw]
Subject: [PATCH 03/15] lightnvm: add minor version to generic geometry

Separate the version between major and minor on the generic geometry and
represent it through sysfs in the 2.0 path. The 1.2 path only shows the
major version to preserve the existing user space interface.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/core.c | 4 ++--
drivers/nvme/host/lightnvm.c | 25 ++++++++++++++++++++-----
include/linux/lightnvm.h | 3 ++-
3 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 9a417d9cdf0c..c4f72fbad2bf 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -890,8 +890,8 @@ static int nvm_init(struct nvm_dev *dev)
goto err;
}

- pr_debug("nvm: ver:%u nvm_vendor:%x\n",
- geo->ver_id,
+ pr_debug("nvm: ver:%u.%u nvm_vendor:%x\n",
+ geo->major_ver_id, geo->minor_ver_id,
geo->vmnt);

ret = nvm_core_init(dev);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 5b2024ebac76..a600e70b6e6b 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -295,7 +295,9 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
return -EINVAL;
}

- geo->ver_id = id->ver_id;
+ /* 1.2 spec. only reports a single version id - unfold */
+ geo->major_ver_id = id->ver_id;
+ geo->minor_ver_id = 2;

geo->nr_chnls = src->num_ch;
geo->nr_luns = src->num_lun;
@@ -380,7 +382,14 @@ static void nvme_nvm_set_addr_20(struct nvm_addr_format *dst,
static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
struct nvm_geo *geo)
{
- geo->ver_id = id->mjr;
+ geo->major_ver_id = id->mjr;
+ geo->minor_ver_id = id->mnr;
+
+ if (!(geo->major_ver_id == 2 && geo->minor_ver_id == 0)) {
+ pr_err("nvm: OCSSD version not supported (v%d.%d)\n",
+ geo->major_ver_id, geo->minor_ver_id);
+ return -EINVAL;
+ }

geo->nr_chnls = le16_to_cpu(id->num_grp);
geo->nr_luns = le16_to_cpu(id->num_pu);
@@ -917,7 +926,13 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
attr = &dattr->attr;

if (strcmp(attr->name, "version") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", geo->ver_id);
+ if (geo->major_ver_id == 1)
+ return scnprintf(page, PAGE_SIZE, "%u\n",
+ geo->major_ver_id);
+ else
+ return scnprintf(page, PAGE_SIZE, "%u.%u\n",
+ geo->major_ver_id,
+ geo->minor_ver_id);
} else if (strcmp(attr->name, "capabilities") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", geo->cap);
} else if (strcmp(attr->name, "read_typ") == 0) {
@@ -1171,7 +1186,7 @@ int nvme_nvm_register_sysfs(struct nvme_ns *ns)
if (!ndev)
return -EINVAL;

- switch (geo->ver_id) {
+ switch (geo->major_ver_id) {
case 1:
return sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
&nvm_dev_attr_group_12);
@@ -1188,7 +1203,7 @@ void nvme_nvm_unregister_sysfs(struct nvme_ns *ns)
struct nvm_dev *ndev = ns->ndev;
struct nvm_geo *geo = &ndev->geo;

- switch (geo->ver_id) {
+ switch (geo->major_ver_id) {
case 1:
sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
&nvm_dev_attr_group_12);
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index b9f0d2070de9..4b2ecbf45fd9 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -263,7 +263,8 @@ enum {
/* Instance geometry */
struct nvm_geo {
/* device reported version */
- u8 ver_id;
+ u8 major_ver_id;
+ u8 minor_ver_id;

/* instance specific geometry */
int nr_chnls;
--
2.7.4


2018-02-28 17:14:15

by Javier González

[permalink] [raw]
Subject: [PATCH 01/15] lightnvm: simplify geometry structure.

Currently, the device geometry is stored redundantly in the nvm_id and
nvm_geo structures at a device level. Moreover, when instantiating
targets on a specific number of LUNs, these structures are replicated
and manually modified to fit the instance channel and LUN partitioning.

Instead, create a generic geometry around nvm_geo, which can be used by
(i) the underlying device to describe the geometry of the whole device,
and (ii) instances to describe their geometry independently.

Signed-off-by: Javier González <[email protected]>
---
drivers/lightnvm/core.c | 70 +++-----
drivers/lightnvm/pblk-core.c | 16 +-
drivers/lightnvm/pblk-gc.c | 2 +-
drivers/lightnvm/pblk-init.c | 119 +++++++-------
drivers/lightnvm/pblk-read.c | 2 +-
drivers/lightnvm/pblk-recovery.c | 14 +-
drivers/lightnvm/pblk-rl.c | 2 +-
drivers/lightnvm/pblk-sysfs.c | 39 +++--
drivers/lightnvm/pblk-write.c | 2 +-
drivers/lightnvm/pblk.h | 87 +++++-----
drivers/nvme/host/lightnvm.c | 341 +++++++++++++++++++++++----------------
include/linux/lightnvm.h | 200 +++++++++++------------
12 files changed, 465 insertions(+), 429 deletions(-)

diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 19c46ebb1b91..9a417d9cdf0c 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -155,7 +155,7 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
int blun = lun_begin % dev->geo.nr_luns;
int lunid = 0;
int lun_balanced = 1;
- int prev_nr_luns;
+ int sec_per_lun, prev_nr_luns;
int i, j;

nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1;
@@ -215,18 +215,23 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
if (!tgt_dev)
goto err_ch;

+ /* Inherit device geometry from parent */
memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo));
+
/* Target device only owns a portion of the physical device */
tgt_dev->geo.nr_chnls = nr_chnls;
- tgt_dev->geo.all_luns = nr_luns;
tgt_dev->geo.nr_luns = (lun_balanced) ? prev_nr_luns : -1;
+ tgt_dev->geo.all_luns = nr_luns;
+ tgt_dev->geo.all_chunks = nr_luns * dev->geo.nr_chks;
+
tgt_dev->geo.op = op;
- tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun;
+
+ sec_per_lun = dev->geo.clba * dev->geo.nr_chks;
+ tgt_dev->geo.total_secs = nr_luns * sec_per_lun;
+
tgt_dev->q = dev->q;
tgt_dev->map = dev_map;
tgt_dev->luns = luns;
- memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id));
-
tgt_dev->parent = dev;

return tgt_dev;
@@ -296,8 +301,6 @@ static int __nvm_config_simple(struct nvm_dev *dev,
static int __nvm_config_extended(struct nvm_dev *dev,
struct nvm_ioctl_create_extended *e)
{
- struct nvm_geo *geo = &dev->geo;
-
if (e->lun_begin == 0xFFFF && e->lun_end == 0xFFFF) {
e->lun_begin = 0;
e->lun_end = dev->geo.all_luns - 1;
@@ -311,7 +314,7 @@ static int __nvm_config_extended(struct nvm_dev *dev,
return -EINVAL;
}

- return nvm_config_check_luns(geo, e->lun_begin, e->lun_end);
+ return nvm_config_check_luns(&dev->geo, e->lun_begin, e->lun_end);
}

static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
@@ -406,7 +409,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
tqueue->queuedata = targetdata;

blk_queue_max_hw_sectors(tqueue,
- (dev->geo.sec_size >> 9) * NVM_MAX_VLBA);
+ (dev->geo.csecs >> 9) * NVM_MAX_VLBA);

set_capacity(tdisk, tt->capacity(targetdata));
add_disk(tdisk);
@@ -841,40 +844,9 @@ EXPORT_SYMBOL(nvm_get_tgt_bb_tbl);

static int nvm_core_init(struct nvm_dev *dev)
{
- struct nvm_id *id = &dev->identity;
struct nvm_geo *geo = &dev->geo;
int ret;

- memcpy(&geo->ppaf, &id->ppaf, sizeof(struct nvm_addr_format));
-
- if (id->mtype != 0) {
- pr_err("nvm: memory type not supported\n");
- return -EINVAL;
- }
-
- /* Whole device values */
- geo->nr_chnls = id->num_ch;
- geo->nr_luns = id->num_lun;
-
- /* Generic device geometry values */
- geo->ws_min = id->ws_min;
- geo->ws_opt = id->ws_opt;
- geo->ws_seq = id->ws_seq;
- geo->ws_per_chk = id->ws_per_chk;
- geo->nr_chks = id->num_chk;
- geo->mccap = id->mccap;
-
- geo->sec_per_chk = id->clba;
- geo->sec_per_lun = geo->sec_per_chk * geo->nr_chks;
- geo->all_luns = geo->nr_luns * geo->nr_chnls;
-
- /* 1.2 spec device geometry values */
- geo->plane_mode = 1 << geo->ws_seq;
- geo->nr_planes = geo->ws_opt / geo->ws_min;
- geo->sec_per_pg = geo->ws_min;
- geo->sec_per_pl = geo->sec_per_pg * geo->nr_planes;
-
- dev->total_secs = geo->all_luns * geo->sec_per_lun;
dev->lun_map = kcalloc(BITS_TO_LONGS(geo->all_luns),
sizeof(unsigned long), GFP_KERNEL);
if (!dev->lun_map)
@@ -913,16 +885,14 @@ static int nvm_init(struct nvm_dev *dev)
struct nvm_geo *geo = &dev->geo;
int ret = -EINVAL;

- if (dev->ops->identity(dev, &dev->identity)) {
+ if (dev->ops->identity(dev)) {
pr_err("nvm: device could not be identified\n");
goto err;
}

- if (dev->identity.ver_id != 1 && dev->identity.ver_id != 2) {
- pr_err("nvm: device ver_id %d not supported by kernel.\n",
- dev->identity.ver_id);
- goto err;
- }
+ pr_debug("nvm: ver:%u nvm_vendor:%x\n",
+ geo->ver_id,
+ geo->vmnt);

ret = nvm_core_init(dev);
if (ret) {
@@ -930,10 +900,10 @@ static int nvm_init(struct nvm_dev *dev)
goto err;
}

- pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
- dev->name, geo->sec_per_pg, geo->nr_planes,
- geo->ws_per_chk, geo->nr_chks,
- geo->all_luns, geo->nr_chnls);
+ pr_info("nvm: registered %s [%u/%u/%u/%u/%u]\n",
+ dev->name, geo->ws_min, geo->ws_opt,
+ geo->nr_chks, geo->all_luns,
+ geo->nr_chnls);
return 0;
err:
pr_err("nvm: failed to initialize nvm\n");
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 8848443a0721..169589ddd457 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -613,7 +613,7 @@ static int pblk_line_submit_emeta_io(struct pblk *pblk, struct pblk_line *line,
memset(&rqd, 0, sizeof(struct nvm_rq));

rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
- rq_len = rq_ppas * geo->sec_size;
+ rq_len = rq_ppas * geo->csecs;

bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len,
l_mg->emeta_alloc_type, GFP_KERNEL);
@@ -722,7 +722,7 @@ u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line)
if (bit >= lm->blk_per_line)
return -1;

- return bit * geo->sec_per_pl;
+ return bit * geo->ws_opt;
}

static int pblk_line_submit_smeta_io(struct pblk *pblk, struct pblk_line *line,
@@ -1035,19 +1035,19 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
/* Capture bad block information on line mapping bitmaps */
while ((bit = find_next_bit(line->blk_bitmap, lm->blk_per_line,
bit + 1)) < lm->blk_per_line) {
- off = bit * geo->sec_per_pl;
+ off = bit * geo->ws_opt;
bitmap_shift_left(l_mg->bb_aux, l_mg->bb_template, off,
lm->sec_per_line);
bitmap_or(line->map_bitmap, line->map_bitmap, l_mg->bb_aux,
lm->sec_per_line);
- line->sec_in_line -= geo->sec_per_chk;
+ line->sec_in_line -= geo->clba;
if (bit >= lm->emeta_bb)
nr_bb++;
}

/* Mark smeta metadata sectors as bad sectors */
bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line);
- off = bit * geo->sec_per_pl;
+ off = bit * geo->ws_opt;
bitmap_set(line->map_bitmap, off, lm->smeta_sec);
line->sec_in_line -= lm->smeta_sec;
line->smeta_ssec = off;
@@ -1066,10 +1066,10 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
emeta_secs = lm->emeta_sec[0];
off = lm->sec_per_line;
while (emeta_secs) {
- off -= geo->sec_per_pl;
+ off -= geo->ws_opt;
if (!test_bit(off, line->invalid_bitmap)) {
- bitmap_set(line->invalid_bitmap, off, geo->sec_per_pl);
- emeta_secs -= geo->sec_per_pl;
+ bitmap_set(line->invalid_bitmap, off, geo->ws_opt);
+ emeta_secs -= geo->ws_opt;
}
}

diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c
index 320f99af99e9..6851a5c67189 100644
--- a/drivers/lightnvm/pblk-gc.c
+++ b/drivers/lightnvm/pblk-gc.c
@@ -88,7 +88,7 @@ static void pblk_gc_line_ws(struct work_struct *work)

up(&gc->gc_sem);

- gc_rq->data = vmalloc(gc_rq->nr_secs * geo->sec_size);
+ gc_rq->data = vmalloc(gc_rq->nr_secs * geo->csecs);
if (!gc_rq->data) {
pr_err("pblk: could not GC line:%d (%d/%d)\n",
line->id, *line->vsc, gc_rq->nr_secs);
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 25fc70ca07f7..9b5ee05c3028 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -146,7 +146,7 @@ static int pblk_rwb_init(struct pblk *pblk)
return -ENOMEM;

power_size = get_count_order(nr_entries);
- power_seg_sz = get_count_order(geo->sec_size);
+ power_seg_sz = get_count_order(geo->csecs);

return pblk_rb_init(&pblk->rwb, entries, power_size, power_seg_sz);
}
@@ -154,11 +154,11 @@ static int pblk_rwb_init(struct pblk *pblk)
/* Minimum pages needed within a lun */
#define ADDR_POOL_SIZE 64

-static int pblk_set_ppaf(struct pblk *pblk)
+static int pblk_set_addrf_12(struct nvm_geo *geo,
+ struct nvm_addr_format_12 *dst)
{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
- struct nvm_addr_format ppaf = geo->ppaf;
+ struct nvm_addr_format_12 *src =
+ (struct nvm_addr_format_12 *)&geo->addrf;
int power_len;

/* Re-calculate channel and lun format to adapt to configuration */
@@ -167,34 +167,50 @@ static int pblk_set_ppaf(struct pblk *pblk)
pr_err("pblk: supports only power-of-two channel config.\n");
return -EINVAL;
}
- ppaf.ch_len = power_len;
+ dst->ch_len = power_len;

power_len = get_count_order(geo->nr_luns);
if (1 << power_len != geo->nr_luns) {
pr_err("pblk: supports only power-of-two LUN config.\n");
return -EINVAL;
}
- ppaf.lun_len = power_len;
+ dst->lun_len = power_len;

- pblk->ppaf.sec_offset = 0;
- pblk->ppaf.pln_offset = ppaf.sect_len;
- pblk->ppaf.ch_offset = pblk->ppaf.pln_offset + ppaf.pln_len;
- pblk->ppaf.lun_offset = pblk->ppaf.ch_offset + ppaf.ch_len;
- pblk->ppaf.pg_offset = pblk->ppaf.lun_offset + ppaf.lun_len;
- pblk->ppaf.blk_offset = pblk->ppaf.pg_offset + ppaf.pg_len;
- pblk->ppaf.sec_mask = (1ULL << ppaf.sect_len) - 1;
- pblk->ppaf.pln_mask = ((1ULL << ppaf.pln_len) - 1) <<
- pblk->ppaf.pln_offset;
- pblk->ppaf.ch_mask = ((1ULL << ppaf.ch_len) - 1) <<
- pblk->ppaf.ch_offset;
- pblk->ppaf.lun_mask = ((1ULL << ppaf.lun_len) - 1) <<
- pblk->ppaf.lun_offset;
- pblk->ppaf.pg_mask = ((1ULL << ppaf.pg_len) - 1) <<
- pblk->ppaf.pg_offset;
- pblk->ppaf.blk_mask = ((1ULL << ppaf.blk_len) - 1) <<
- pblk->ppaf.blk_offset;
+ dst->blk_len = src->blk_len;
+ dst->pg_len = src->pg_len;
+ dst->pln_len = src->pln_len;
+ dst->sect_len = src->sect_len;

- pblk->ppaf_bitsize = pblk->ppaf.blk_offset + ppaf.blk_len;
+ dst->sect_offset = 0;
+ dst->pln_offset = dst->sect_len;
+ dst->ch_offset = dst->pln_offset + dst->pln_len;
+ dst->lun_offset = dst->ch_offset + dst->ch_len;
+ dst->pg_offset = dst->lun_offset + dst->lun_len;
+ dst->blk_offset = dst->pg_offset + dst->pg_len;
+
+ dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
+ dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
+ dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
+ dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
+ dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
+ dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
+
+ return dst->blk_offset + src->blk_len;
+}
+
+static int pblk_set_ppaf(struct pblk *pblk)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ int mod;
+
+ div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
+ if (mod) {
+ pr_err("pblk: bad configuration of sectors/pages\n");
+ return -EINVAL;
+ }
+
+ pblk->ppaf_bitsize = pblk_set_addrf_12(geo, (void *)&pblk->ppaf);

return 0;
}
@@ -253,8 +269,7 @@ static int pblk_core_init(struct pblk *pblk)
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;

- pblk->pgs_in_buffer = NVM_MEM_PAGE_WRITE * geo->sec_per_pg *
- geo->nr_planes * geo->all_luns;
+ pblk->pgs_in_buffer = geo->mw_cunits * geo->all_luns;

if (pblk_init_global_caches(pblk))
return -ENOMEM;
@@ -552,18 +567,18 @@ static unsigned int calc_emeta_len(struct pblk *pblk)
/* Round to sector size so that lba_list starts on its own sector */
lm->emeta_sec[1] = DIV_ROUND_UP(
sizeof(struct line_emeta) + lm->blk_bitmap_len +
- sizeof(struct wa_counters), geo->sec_size);
- lm->emeta_len[1] = lm->emeta_sec[1] * geo->sec_size;
+ sizeof(struct wa_counters), geo->csecs);
+ lm->emeta_len[1] = lm->emeta_sec[1] * geo->csecs;

/* Round to sector size so that vsc_list starts on its own sector */
lm->dsec_per_line = lm->sec_per_line - lm->emeta_sec[0];
lm->emeta_sec[2] = DIV_ROUND_UP(lm->dsec_per_line * sizeof(u64),
- geo->sec_size);
- lm->emeta_len[2] = lm->emeta_sec[2] * geo->sec_size;
+ geo->csecs);
+ lm->emeta_len[2] = lm->emeta_sec[2] * geo->csecs;

lm->emeta_sec[3] = DIV_ROUND_UP(l_mg->nr_lines * sizeof(u32),
- geo->sec_size);
- lm->emeta_len[3] = lm->emeta_sec[3] * geo->sec_size;
+ geo->csecs);
+ lm->emeta_len[3] = lm->emeta_sec[3] * geo->csecs;

lm->vsc_list_len = l_mg->nr_lines * sizeof(u32);

@@ -594,13 +609,13 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
* on user capacity consider only provisioned blocks
*/
pblk->rl.total_blocks = nr_free_blks;
- pblk->rl.nr_secs = nr_free_blks * geo->sec_per_chk;
+ pblk->rl.nr_secs = nr_free_blks * geo->clba;

/* Consider sectors used for metadata */
sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
- blk_meta = DIV_ROUND_UP(sec_meta, geo->sec_per_chk);
+ blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);

- pblk->capacity = (provisioned - blk_meta) * geo->sec_per_chk;
+ pblk->capacity = (provisioned - blk_meta) * geo->clba;

atomic_set(&pblk->rl.free_blocks, nr_free_blks);
atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
@@ -711,10 +726,10 @@ static int pblk_lines_init(struct pblk *pblk)
void *chunk_log;
unsigned int smeta_len, emeta_len;
long nr_bad_blks = 0, nr_free_blks = 0;
- int bb_distance, max_write_ppas, mod;
+ int bb_distance, max_write_ppas;
int i, ret;

- pblk->min_write_pgs = geo->sec_per_pl * (geo->sec_size / PAGE_SIZE);
+ pblk->min_write_pgs = geo->ws_opt * (geo->csecs / PAGE_SIZE);
max_write_ppas = pblk->min_write_pgs * geo->all_luns;
pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA);
pblk_set_sec_per_write(pblk, pblk->min_write_pgs);
@@ -725,19 +740,13 @@ static int pblk_lines_init(struct pblk *pblk)
return -EINVAL;
}

- div_u64_rem(geo->sec_per_chk, pblk->min_write_pgs, &mod);
- if (mod) {
- pr_err("pblk: bad configuration of sectors/pages\n");
- return -EINVAL;
- }
-
l_mg->nr_lines = geo->nr_chks;
l_mg->log_line = l_mg->data_line = NULL;
l_mg->l_seq_nr = l_mg->d_seq_nr = 0;
l_mg->nr_free_lines = 0;
bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES);

- lm->sec_per_line = geo->sec_per_chk * geo->all_luns;
+ lm->sec_per_line = geo->clba * geo->all_luns;
lm->blk_per_line = geo->all_luns;
lm->blk_bitmap_len = BITS_TO_LONGS(geo->all_luns) * sizeof(long);
lm->sec_bitmap_len = BITS_TO_LONGS(lm->sec_per_line) * sizeof(long);
@@ -751,8 +760,8 @@ static int pblk_lines_init(struct pblk *pblk)
*/
i = 1;
add_smeta_page:
- lm->smeta_sec = i * geo->sec_per_pl;
- lm->smeta_len = lm->smeta_sec * geo->sec_size;
+ lm->smeta_sec = i * geo->ws_opt;
+ lm->smeta_len = lm->smeta_sec * geo->csecs;

smeta_len = sizeof(struct line_smeta) + lm->lun_bitmap_len;
if (smeta_len > lm->smeta_len) {
@@ -765,8 +774,8 @@ static int pblk_lines_init(struct pblk *pblk)
*/
i = 1;
add_emeta_page:
- lm->emeta_sec[0] = i * geo->sec_per_pl;
- lm->emeta_len[0] = lm->emeta_sec[0] * geo->sec_size;
+ lm->emeta_sec[0] = i * geo->ws_opt;
+ lm->emeta_len[0] = lm->emeta_sec[0] * geo->csecs;

emeta_len = calc_emeta_len(pblk);
if (emeta_len > lm->emeta_len[0]) {
@@ -779,7 +788,7 @@ static int pblk_lines_init(struct pblk *pblk)
lm->min_blk_line = 1;
if (geo->all_luns > 1)
lm->min_blk_line += DIV_ROUND_UP(lm->smeta_sec +
- lm->emeta_sec[0], geo->sec_per_chk);
+ lm->emeta_sec[0], geo->clba);

if (lm->min_blk_line > lm->blk_per_line) {
pr_err("pblk: config. not supported. Min. LUN in line:%d\n",
@@ -803,9 +812,9 @@ static int pblk_lines_init(struct pblk *pblk)
goto fail_free_bb_template;
}

- bb_distance = (geo->all_luns) * geo->sec_per_pl;
+ bb_distance = (geo->all_luns) * geo->ws_opt;
for (i = 0; i < lm->sec_per_line; i += bb_distance)
- bitmap_set(l_mg->bb_template, i, geo->sec_per_pl);
+ bitmap_set(l_mg->bb_template, i, geo->ws_opt);

INIT_LIST_HEAD(&l_mg->free_list);
INIT_LIST_HEAD(&l_mg->corrupt_list);
@@ -982,9 +991,9 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
struct pblk *pblk;
int ret;

- if (dev->identity.dom & NVM_RSP_L2P) {
+ if (dev->geo.dom & NVM_RSP_L2P) {
pr_err("pblk: host-side L2P table not supported. (%x)\n",
- dev->identity.dom);
+ dev->geo.dom);
return ERR_PTR(-EINVAL);
}

@@ -1092,7 +1101,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,

blk_queue_write_cache(tqueue, true, false);

- tqueue->limits.discard_granularity = geo->sec_per_chk * geo->sec_size;
+ tqueue->limits.discard_granularity = geo->clba * geo->csecs;
tqueue->limits.discard_alignment = 0;
blk_queue_max_discard_sectors(tqueue, UINT_MAX >> 9);
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, tqueue);
diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
index 2f761283f43e..9eee10f69df0 100644
--- a/drivers/lightnvm/pblk-read.c
+++ b/drivers/lightnvm/pblk-read.c
@@ -563,7 +563,7 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
if (!(gc_rq->secs_to_gc))
goto out;

- data_len = (gc_rq->secs_to_gc) * geo->sec_size;
+ data_len = (gc_rq->secs_to_gc) * geo->csecs;
bio = pblk_bio_map_addr(pblk, gc_rq->data, gc_rq->secs_to_gc, data_len,
PBLK_VMALLOC_META, GFP_KERNEL);
if (IS_ERR(bio)) {
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
index aaab9a5c17cc..26356429dc72 100644
--- a/drivers/lightnvm/pblk-recovery.c
+++ b/drivers/lightnvm/pblk-recovery.c
@@ -184,7 +184,7 @@ static int pblk_calc_sec_in_line(struct pblk *pblk, struct pblk_line *line)
int nr_bb = bitmap_weight(line->blk_bitmap, lm->blk_per_line);

return lm->sec_per_line - lm->smeta_sec - lm->emeta_sec[0] -
- nr_bb * geo->sec_per_chk;
+ nr_bb * geo->clba;
}

struct pblk_recov_alloc {
@@ -232,7 +232,7 @@ static int pblk_recov_read_oob(struct pblk *pblk, struct pblk_line *line,
rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
if (!rq_ppas)
rq_ppas = pblk->min_write_pgs;
- rq_len = rq_ppas * geo->sec_size;
+ rq_len = rq_ppas * geo->csecs;

bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
if (IS_ERR(bio))
@@ -351,7 +351,7 @@ static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
if (!pad_rq)
return -ENOMEM;

- data = vzalloc(pblk->max_write_pgs * geo->sec_size);
+ data = vzalloc(pblk->max_write_pgs * geo->csecs);
if (!data) {
ret = -ENOMEM;
goto free_rq;
@@ -368,7 +368,7 @@ static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
goto fail_free_pad;
}

- rq_len = rq_ppas * geo->sec_size;
+ rq_len = rq_ppas * geo->csecs;

meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list);
if (!meta_list) {
@@ -509,7 +509,7 @@ static int pblk_recov_scan_all_oob(struct pblk *pblk, struct pblk_line *line,
rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
if (!rq_ppas)
rq_ppas = pblk->min_write_pgs;
- rq_len = rq_ppas * geo->sec_size;
+ rq_len = rq_ppas * geo->csecs;

bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
if (IS_ERR(bio))
@@ -640,7 +640,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
if (!rq_ppas)
rq_ppas = pblk->min_write_pgs;
- rq_len = rq_ppas * geo->sec_size;
+ rq_len = rq_ppas * geo->csecs;

bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
if (IS_ERR(bio))
@@ -745,7 +745,7 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line)
ppa_list = (void *)(meta_list) + pblk_dma_meta_size;
dma_ppa_list = dma_meta_list + pblk_dma_meta_size;

- data = kcalloc(pblk->max_write_pgs, geo->sec_size, GFP_KERNEL);
+ data = kcalloc(pblk->max_write_pgs, geo->csecs, GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto free_meta_list;
diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c
index 0d457b162f23..883a7113b19d 100644
--- a/drivers/lightnvm/pblk-rl.c
+++ b/drivers/lightnvm/pblk-rl.c
@@ -200,7 +200,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)

/* Consider sectors used for metadata */
sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
- blk_meta = DIV_ROUND_UP(sec_meta, geo->sec_per_chk);
+ blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);

rl->high = pblk->op_blks - blk_meta - lm->blk_per_line;
rl->high_pw = get_count_order(rl->high);
diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
index 1680ce0a828d..33199c6af267 100644
--- a/drivers/lightnvm/pblk-sysfs.c
+++ b/drivers/lightnvm/pblk-sysfs.c
@@ -113,26 +113,31 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
+ struct nvm_addr_format_12 *ppaf;
+ struct nvm_addr_format_12 *geo_ppaf;
ssize_t sz = 0;

- sz = snprintf(page, PAGE_SIZE - sz,
- "g:(b:%d)blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
- pblk->ppaf_bitsize,
- pblk->ppaf.blk_offset, geo->ppaf.blk_len,
- pblk->ppaf.pg_offset, geo->ppaf.pg_len,
- pblk->ppaf.lun_offset, geo->ppaf.lun_len,
- pblk->ppaf.ch_offset, geo->ppaf.ch_len,
- pblk->ppaf.pln_offset, geo->ppaf.pln_len,
- pblk->ppaf.sec_offset, geo->ppaf.sect_len);
+ ppaf = (struct nvm_addr_format_12 *)&pblk->ppaf;
+ geo_ppaf = (struct nvm_addr_format_12 *)&geo->addrf;
+
+ sz = snprintf(page, PAGE_SIZE,
+ "pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
+ pblk->ppaf_bitsize,
+ ppaf->ch_offset, ppaf->ch_len,
+ ppaf->lun_offset, ppaf->lun_len,
+ ppaf->blk_offset, ppaf->blk_len,
+ ppaf->pg_offset, ppaf->pg_len,
+ ppaf->pln_offset, ppaf->pln_len,
+ ppaf->sect_offset, ppaf->sect_len);

sz += snprintf(page + sz, PAGE_SIZE - sz,
- "d:blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
- geo->ppaf.blk_offset, geo->ppaf.blk_len,
- geo->ppaf.pg_offset, geo->ppaf.pg_len,
- geo->ppaf.lun_offset, geo->ppaf.lun_len,
- geo->ppaf.ch_offset, geo->ppaf.ch_len,
- geo->ppaf.pln_offset, geo->ppaf.pln_len,
- geo->ppaf.sect_offset, geo->ppaf.sect_len);
+ "device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
+ geo_ppaf->ch_offset, geo_ppaf->ch_len,
+ geo_ppaf->lun_offset, geo_ppaf->lun_len,
+ geo_ppaf->blk_offset, geo_ppaf->blk_len,
+ geo_ppaf->pg_offset, geo_ppaf->pg_len,
+ geo_ppaf->pln_offset, geo_ppaf->pln_len,
+ geo_ppaf->sect_offset, geo_ppaf->sect_len);

return sz;
}
@@ -288,7 +293,7 @@ static ssize_t pblk_sysfs_lines_info(struct pblk *pblk, char *page)
"blk_line:%d, sec_line:%d, sec_blk:%d\n",
lm->blk_per_line,
lm->sec_per_line,
- geo->sec_per_chk);
+ geo->clba);

return sz;
}
diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c
index aae86ed60b98..3e6f1ebd743a 100644
--- a/drivers/lightnvm/pblk-write.c
+++ b/drivers/lightnvm/pblk-write.c
@@ -333,7 +333,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line)
m_ctx = nvm_rq_to_pdu(rqd);
m_ctx->private = meta_line;

- rq_len = rq_ppas * geo->sec_size;
+ rq_len = rq_ppas * geo->csecs;
data = ((void *)emeta->buf) + emeta->mem;

bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len,
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index f0309d8172c0..b29c1e6698aa 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -551,21 +551,6 @@ struct pblk_line_meta {
unsigned int meta_distance; /* Distance between data and metadata */
};

-struct pblk_addr_format {
- u64 ch_mask;
- u64 lun_mask;
- u64 pln_mask;
- u64 blk_mask;
- u64 pg_mask;
- u64 sec_mask;
- u8 ch_offset;
- u8 lun_offset;
- u8 pln_offset;
- u8 blk_offset;
- u8 pg_offset;
- u8 sec_offset;
-};
-
enum {
PBLK_STATE_RUNNING = 0,
PBLK_STATE_STOPPING = 1,
@@ -585,8 +570,8 @@ struct pblk {
struct pblk_line_mgmt l_mg; /* Line management */
struct pblk_line_meta lm; /* Line metadata */

+ struct nvm_addr_format ppaf;
int ppaf_bitsize;
- struct pblk_addr_format ppaf;

struct pblk_rb rwb;

@@ -941,14 +926,12 @@ static inline int pblk_line_vsc(struct pblk_line *line)
return le32_to_cpu(*line->vsc);
}

-#define NVM_MEM_PAGE_WRITE (8)
-
static inline int pblk_pad_distance(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;

- return NVM_MEM_PAGE_WRITE * geo->all_luns * geo->sec_per_pl;
+ return geo->mw_cunits * geo->all_luns * geo->ws_opt;
}

static inline int pblk_ppa_to_line(struct ppa_addr p)
@@ -964,15 +947,17 @@ static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
u64 line_id)
{
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&pblk->ppaf;
struct ppa_addr ppa;

ppa.ppa = 0;
ppa.g.blk = line_id;
- ppa.g.pg = (paddr & pblk->ppaf.pg_mask) >> pblk->ppaf.pg_offset;
- ppa.g.lun = (paddr & pblk->ppaf.lun_mask) >> pblk->ppaf.lun_offset;
- ppa.g.ch = (paddr & pblk->ppaf.ch_mask) >> pblk->ppaf.ch_offset;
- ppa.g.pl = (paddr & pblk->ppaf.pln_mask) >> pblk->ppaf.pln_offset;
- ppa.g.sec = (paddr & pblk->ppaf.sec_mask) >> pblk->ppaf.sec_offset;
+ ppa.g.pg = (paddr & ppaf->pg_mask) >> ppaf->pg_offset;
+ ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
+ ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
+ ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
+ ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sect_offset;

return ppa;
}
@@ -980,13 +965,15 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
struct ppa_addr p)
{
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&pblk->ppaf;
u64 paddr;

- paddr = (u64)p.g.pg << pblk->ppaf.pg_offset;
- paddr |= (u64)p.g.lun << pblk->ppaf.lun_offset;
- paddr |= (u64)p.g.ch << pblk->ppaf.ch_offset;
- paddr |= (u64)p.g.pl << pblk->ppaf.pln_offset;
- paddr |= (u64)p.g.sec << pblk->ppaf.sec_offset;
+ paddr = (u64)p.g.ch << ppaf->ch_offset;
+ paddr |= (u64)p.g.lun << ppaf->lun_offset;
+ paddr |= (u64)p.g.pg << ppaf->pg_offset;
+ paddr |= (u64)p.g.pl << ppaf->pln_offset;
+ paddr |= (u64)p.g.sec << ppaf->sect_offset;

return paddr;
}
@@ -1003,18 +990,15 @@ static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
ppa64.c.line = ppa32 & ((~0U) >> 1);
ppa64.c.is_cached = 1;
} else {
- ppa64.g.blk = (ppa32 & pblk->ppaf.blk_mask) >>
- pblk->ppaf.blk_offset;
- ppa64.g.pg = (ppa32 & pblk->ppaf.pg_mask) >>
- pblk->ppaf.pg_offset;
- ppa64.g.lun = (ppa32 & pblk->ppaf.lun_mask) >>
- pblk->ppaf.lun_offset;
- ppa64.g.ch = (ppa32 & pblk->ppaf.ch_mask) >>
- pblk->ppaf.ch_offset;
- ppa64.g.pl = (ppa32 & pblk->ppaf.pln_mask) >>
- pblk->ppaf.pln_offset;
- ppa64.g.sec = (ppa32 & pblk->ppaf.sec_mask) >>
- pblk->ppaf.sec_offset;
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&pblk->ppaf;
+
+ ppa64.g.ch = (ppa32 & ppaf->ch_mask) >> ppaf->ch_offset;
+ ppa64.g.lun = (ppa32 & ppaf->lun_mask) >> ppaf->lun_offset;
+ ppa64.g.blk = (ppa32 & ppaf->blk_mask) >> ppaf->blk_offset;
+ ppa64.g.pg = (ppa32 & ppaf->pg_mask) >> ppaf->pg_offset;
+ ppa64.g.pl = (ppa32 & ppaf->pln_mask) >> ppaf->pln_offset;
+ ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> ppaf->sect_offset;
}

return ppa64;
@@ -1030,12 +1014,15 @@ static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
ppa32 |= ppa64.c.line;
ppa32 |= 1U << 31;
} else {
- ppa32 |= ppa64.g.blk << pblk->ppaf.blk_offset;
- ppa32 |= ppa64.g.pg << pblk->ppaf.pg_offset;
- ppa32 |= ppa64.g.lun << pblk->ppaf.lun_offset;
- ppa32 |= ppa64.g.ch << pblk->ppaf.ch_offset;
- ppa32 |= ppa64.g.pl << pblk->ppaf.pln_offset;
- ppa32 |= ppa64.g.sec << pblk->ppaf.sec_offset;
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&pblk->ppaf;
+
+ ppa32 |= ppa64.g.ch << ppaf->ch_offset;
+ ppa32 |= ppa64.g.lun << ppaf->lun_offset;
+ ppa32 |= ppa64.g.blk << ppaf->blk_offset;
+ ppa32 |= ppa64.g.pg << ppaf->pg_offset;
+ ppa32 |= ppa64.g.pl << ppaf->pln_offset;
+ ppa32 |= ppa64.g.sec << ppaf->sect_offset;
}

return ppa32;
@@ -1229,10 +1216,10 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev,
if (!ppa->c.is_cached &&
ppa->g.ch < geo->nr_chnls &&
ppa->g.lun < geo->nr_luns &&
- ppa->g.pl < geo->nr_planes &&
+ ppa->g.pl < geo->num_pln &&
ppa->g.blk < geo->nr_chks &&
- ppa->g.pg < geo->ws_per_chk &&
- ppa->g.sec < geo->sec_per_pg)
+ ppa->g.pg < geo->num_pg &&
+ ppa->g.sec < geo->ws_min)
continue;

print_ppa(ppa, "boundary", i);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 839c0b96466a..e276ace28c64 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -152,8 +152,8 @@ struct nvme_nvm_id12_addrf {
__u8 blk_len;
__u8 pg_offset;
__u8 pg_len;
- __u8 sect_offset;
- __u8 sect_len;
+ __u8 sec_offset;
+ __u8 sec_len;
__u8 res[4];
} __packed;

@@ -254,106 +254,161 @@ static inline void _nvme_nvm_check_size(void)
BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
}

-static int init_grp(struct nvm_id *nvm_id, struct nvme_nvm_id12 *id12)
+static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
+ struct nvme_nvm_id12_addrf *src)
+{
+ dst->ch_len = src->ch_len;
+ dst->lun_len = src->lun_len;
+ dst->blk_len = src->blk_len;
+ dst->pg_len = src->pg_len;
+ dst->pln_len = src->pln_len;
+ dst->sect_len = src->sec_len;
+
+ dst->ch_offset = src->ch_offset;
+ dst->lun_offset = src->lun_offset;
+ dst->blk_offset = src->blk_offset;
+ dst->pg_offset = src->pg_offset;
+ dst->pln_offset = src->pln_offset;
+ dst->sect_offset = src->sec_offset;
+
+ dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
+ dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
+ dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
+ dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
+ dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
+ dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
+}
+
+static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
+ struct nvm_geo *geo)
{
struct nvme_nvm_id12_grp *src;
int sec_per_pg, sec_per_pl, pg_per_blk;

- if (id12->cgrps != 1)
+ if (id->cgrps != 1)
return -EINVAL;

- src = &id12->grp;
+ src = &id->grp;

- nvm_id->mtype = src->mtype;
- nvm_id->fmtype = src->fmtype;
+ if (src->mtype != 0) {
+ pr_err("nvm: memory type not supported\n");
+ return -EINVAL;
+ }
+
+ geo->ver_id = id->ver_id;
+
+ geo->nr_chnls = src->num_ch;
+ geo->nr_luns = src->num_lun;
+ geo->all_luns = geo->nr_chnls * geo->nr_luns;

- nvm_id->num_ch = src->num_ch;
- nvm_id->num_lun = src->num_lun;
+ geo->nr_chks = le16_to_cpu(src->num_chk);

- nvm_id->num_chk = le16_to_cpu(src->num_chk);
- nvm_id->csecs = le16_to_cpu(src->csecs);
- nvm_id->sos = le16_to_cpu(src->sos);
+ geo->csecs = le16_to_cpu(src->csecs);
+ geo->sos = le16_to_cpu(src->sos);

pg_per_blk = le16_to_cpu(src->num_pg);
- sec_per_pg = le16_to_cpu(src->fpg_sz) / nvm_id->csecs;
+ sec_per_pg = le16_to_cpu(src->fpg_sz) / geo->csecs;
sec_per_pl = sec_per_pg * src->num_pln;
- nvm_id->clba = sec_per_pl * pg_per_blk;
- nvm_id->ws_per_chk = pg_per_blk;
-
- nvm_id->mpos = le32_to_cpu(src->mpos);
- nvm_id->cpar = le16_to_cpu(src->cpar);
- nvm_id->mccap = le32_to_cpu(src->mccap);
-
- nvm_id->ws_opt = nvm_id->ws_min = sec_per_pg;
- nvm_id->ws_seq = NVM_IO_SNGL_ACCESS;
-
- if (nvm_id->mpos & 0x020202) {
- nvm_id->ws_seq = NVM_IO_DUAL_ACCESS;
- nvm_id->ws_opt <<= 1;
- } else if (nvm_id->mpos & 0x040404) {
- nvm_id->ws_seq = NVM_IO_QUAD_ACCESS;
- nvm_id->ws_opt <<= 2;
+ geo->clba = sec_per_pl * pg_per_blk;
+
+ geo->all_chunks = geo->all_luns * geo->nr_chks;
+ geo->total_secs = geo->clba * geo->all_chunks;
+
+ geo->ws_min = sec_per_pg;
+ geo->ws_opt = sec_per_pg;
+ geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */
+
+ geo->mccap = le32_to_cpu(src->mccap);
+
+ geo->trdt = le32_to_cpu(src->trdt);
+ geo->trdm = le32_to_cpu(src->trdm);
+ geo->tprt = le32_to_cpu(src->tprt);
+ geo->tprm = le32_to_cpu(src->tprm);
+ geo->tbet = le32_to_cpu(src->tbet);
+ geo->tbem = le32_to_cpu(src->tbem);
+
+ /* 1.2 compatibility */
+ geo->vmnt = id->vmnt;
+ geo->cap = le32_to_cpu(id->cap);
+ geo->dom = le32_to_cpu(id->dom);
+
+ geo->mtype = src->mtype;
+ geo->fmtype = src->fmtype;
+
+ geo->cpar = le16_to_cpu(src->cpar);
+ geo->mpos = le32_to_cpu(src->mpos);
+
+ geo->plane_mode = NVM_PLANE_SINGLE;
+
+ if (geo->mpos & 0x020202) {
+ geo->plane_mode = NVM_PLANE_DOUBLE;
+ geo->ws_opt <<= 1;
+ } else if (geo->mpos & 0x040404) {
+ geo->plane_mode = NVM_PLANE_QUAD;
+ geo->ws_opt <<= 2;
}

- nvm_id->trdt = le32_to_cpu(src->trdt);
- nvm_id->trdm = le32_to_cpu(src->trdm);
- nvm_id->tprt = le32_to_cpu(src->tprt);
- nvm_id->tprm = le32_to_cpu(src->tprm);
- nvm_id->tbet = le32_to_cpu(src->tbet);
- nvm_id->tbem = le32_to_cpu(src->tbem);
-
- /* 1.2 compatibility */
- nvm_id->num_pln = src->num_pln;
- nvm_id->num_pg = le16_to_cpu(src->num_pg);
- nvm_id->fpg_sz = le16_to_cpu(src->fpg_sz);
+ geo->num_pln = src->num_pln;
+ geo->num_pg = le16_to_cpu(src->num_pg);
+ geo->fpg_sz = le16_to_cpu(src->fpg_sz);
+
+ nvme_nvm_set_addr_12((struct nvm_addr_format_12 *)&geo->addrf,
+ &id->ppaf);

return 0;
}

-static int nvme_nvm_setup_12(struct nvm_dev *nvmdev, struct nvm_id *nvm_id,
- struct nvme_nvm_id12 *id)
+static void nvme_nvm_set_addr_20(struct nvm_addr_format *dst,
+ struct nvme_nvm_id20_addrf *src)
{
- nvm_id->ver_id = id->ver_id;
- nvm_id->vmnt = id->vmnt;
- nvm_id->cap = le32_to_cpu(id->cap);
- nvm_id->dom = le32_to_cpu(id->dom);
- memcpy(&nvm_id->ppaf, &id->ppaf,
- sizeof(struct nvm_addr_format));
-
- return init_grp(nvm_id, id);
+ dst->ch_len = src->grp_len;
+ dst->lun_len = src->pu_len;
+ dst->chk_len = src->chk_len;
+ dst->sec_len = src->lba_len;
+
+ dst->sec_offset = 0;
+ dst->chk_offset = dst->sec_len;
+ dst->lun_offset = dst->chk_offset + dst->chk_len;
+ dst->ch_offset = dst->lun_offset + dst->lun_len;
+
+ dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
+ dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
+ dst->chk_mask = ((1ULL << dst->chk_len) - 1) << dst->chk_offset;
+ dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset;
}

-static int nvme_nvm_setup_20(struct nvm_dev *nvmdev, struct nvm_id *nvm_id,
- struct nvme_nvm_id20 *id)
+static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
+ struct nvm_geo *geo)
{
- nvm_id->ver_id = id->mjr;
+ geo->ver_id = id->mjr;
+
+ geo->nr_chnls = le16_to_cpu(id->num_grp);
+ geo->nr_luns = le16_to_cpu(id->num_pu);
+ geo->all_luns = geo->nr_chnls * geo->nr_luns;

- nvm_id->num_ch = le16_to_cpu(id->num_grp);
- nvm_id->num_lun = le16_to_cpu(id->num_pu);
- nvm_id->num_chk = le32_to_cpu(id->num_chk);
- nvm_id->clba = le32_to_cpu(id->clba);
+ geo->nr_chks = le32_to_cpu(id->num_chk);
+ geo->clba = le32_to_cpu(id->clba);

- nvm_id->ws_min = le32_to_cpu(id->ws_min);
- nvm_id->ws_opt = le32_to_cpu(id->ws_opt);
- nvm_id->mw_cunits = le32_to_cpu(id->mw_cunits);
+ geo->all_chunks = geo->all_luns * geo->nr_chks;
+ geo->total_secs = geo->clba * geo->all_chunks;

- nvm_id->trdt = le32_to_cpu(id->trdt);
- nvm_id->trdm = le32_to_cpu(id->trdm);
- nvm_id->tprt = le32_to_cpu(id->twrt);
- nvm_id->tprm = le32_to_cpu(id->twrm);
- nvm_id->tbet = le32_to_cpu(id->tcrst);
- nvm_id->tbem = le32_to_cpu(id->tcrsm);
+ geo->ws_min = le32_to_cpu(id->ws_min);
+ geo->ws_opt = le32_to_cpu(id->ws_opt);
+ geo->mw_cunits = le32_to_cpu(id->mw_cunits);

- /* calculated values */
- nvm_id->ws_per_chk = nvm_id->clba / nvm_id->ws_min;
+ geo->trdt = le32_to_cpu(id->trdt);
+ geo->trdm = le32_to_cpu(id->trdm);
+ geo->tprt = le32_to_cpu(id->twrt);
+ geo->tprm = le32_to_cpu(id->twrm);
+ geo->tbet = le32_to_cpu(id->tcrst);
+ geo->tbem = le32_to_cpu(id->tcrsm);

- /* 1.2 compatibility */
- nvm_id->ws_seq = NVM_IO_SNGL_ACCESS;
+ nvme_nvm_set_addr_20(&geo->addrf, &id->lbaf);

return 0;
}

-static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
+static int nvme_nvm_identity(struct nvm_dev *nvmdev)
{
struct nvme_ns *ns = nvmdev->q->queuedata;
struct nvme_nvm_id12 *id;
@@ -380,18 +435,18 @@ static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
*/
switch (id->ver_id) {
case 1:
- ret = nvme_nvm_setup_12(nvmdev, nvm_id, id);
+ ret = nvme_nvm_setup_12(id, &nvmdev->geo);
break;
case 2:
- ret = nvme_nvm_setup_20(nvmdev, nvm_id,
- (struct nvme_nvm_id20 *)id);
+ ret = nvme_nvm_setup_20((struct nvme_nvm_id20 *)id,
+ &nvmdev->geo);
break;
default:
- dev_err(ns->ctrl->device,
- "OCSSD revision not supported (%d)\n",
- nvm_id->ver_id);
+ dev_err(ns->ctrl->device, "OCSSD revision not supported (%d)\n",
+ id->ver_id);
ret = -EINVAL;
}
+
out:
kfree(id);
return ret;
@@ -406,7 +461,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
struct nvme_ctrl *ctrl = ns->ctrl;
struct nvme_nvm_command c = {};
struct nvme_nvm_bb_tbl *bb_tbl;
- int nr_blks = geo->nr_chks * geo->plane_mode;
+ int nr_blks = geo->nr_chks * geo->num_pln;
int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blks;
int ret = 0;

@@ -447,7 +502,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
goto out;
}

- memcpy(blks, bb_tbl->blk, geo->nr_chks * geo->plane_mode);
+ memcpy(blks, bb_tbl->blk, geo->nr_chks * geo->num_pln);
out:
kfree(bb_tbl);
return ret;
@@ -815,9 +870,10 @@ int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg)
void nvme_nvm_update_nvm_info(struct nvme_ns *ns)
{
struct nvm_dev *ndev = ns->ndev;
+ struct nvm_geo *geo = &ndev->geo;

- ndev->identity.csecs = ndev->geo.sec_size = 1 << ns->lba_shift;
- ndev->identity.sos = ndev->geo.oob_size = ns->ms;
+ geo->csecs = 1 << ns->lba_shift;
+ geo->sos = ns->ms;
}

int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node)
@@ -850,23 +906,22 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
{
struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
struct nvm_dev *ndev = ns->ndev;
- struct nvm_id *id;
+ struct nvm_geo *geo = &ndev->geo;
struct attribute *attr;

if (!ndev)
return 0;

- id = &ndev->identity;
attr = &dattr->attr;

if (strcmp(attr->name, "version") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->ver_id);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->ver_id);
} else if (strcmp(attr->name, "capabilities") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->cap);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->cap);
} else if (strcmp(attr->name, "read_typ") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->trdt);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdt);
} else if (strcmp(attr->name, "read_max") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->trdm);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdm);
} else {
return scnprintf(page,
PAGE_SIZE,
@@ -875,75 +930,79 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
}
}

+static ssize_t nvm_dev_attr_show_ppaf(struct nvm_addr_format_12 *ppaf,
+ char *page)
+{
+ return scnprintf(page, PAGE_SIZE,
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ ppaf->ch_offset, ppaf->ch_len,
+ ppaf->lun_offset, ppaf->lun_len,
+ ppaf->pln_offset, ppaf->pln_len,
+ ppaf->blk_offset, ppaf->blk_len,
+ ppaf->pg_offset, ppaf->pg_len,
+ ppaf->sect_offset, ppaf->sect_len);
+}
+
static ssize_t nvm_dev_attr_show_12(struct device *dev,
struct device_attribute *dattr, char *page)
{
struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
struct nvm_dev *ndev = ns->ndev;
- struct nvm_id *id;
+ struct nvm_geo *geo = &ndev->geo;
struct attribute *attr;

if (!ndev)
return 0;

- id = &ndev->identity;
attr = &dattr->attr;

if (strcmp(attr->name, "vendor_opcode") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->vmnt);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->vmnt);
} else if (strcmp(attr->name, "device_mode") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->dom);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->dom);
/* kept for compatibility */
} else if (strcmp(attr->name, "media_manager") == 0) {
return scnprintf(page, PAGE_SIZE, "%s\n", "gennvm");
} else if (strcmp(attr->name, "ppa_format") == 0) {
- return scnprintf(page, PAGE_SIZE,
- "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- id->ppaf.ch_offset, id->ppaf.ch_len,
- id->ppaf.lun_offset, id->ppaf.lun_len,
- id->ppaf.pln_offset, id->ppaf.pln_len,
- id->ppaf.blk_offset, id->ppaf.blk_len,
- id->ppaf.pg_offset, id->ppaf.pg_len,
- id->ppaf.sect_offset, id->ppaf.sect_len);
+ return nvm_dev_attr_show_ppaf((void *)&geo->addrf, page);
} else if (strcmp(attr->name, "media_type") == 0) { /* u8 */
- return scnprintf(page, PAGE_SIZE, "%u\n", id->mtype);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->mtype);
} else if (strcmp(attr->name, "flash_media_type") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->fmtype);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->fmtype);
} else if (strcmp(attr->name, "num_channels") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_ch);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
} else if (strcmp(attr->name, "num_luns") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_lun);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
} else if (strcmp(attr->name, "num_planes") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_pln);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pln);
} else if (strcmp(attr->name, "num_blocks") == 0) { /* u16 */
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_chk);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
} else if (strcmp(attr->name, "num_pages") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_pg);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pg);
} else if (strcmp(attr->name, "page_size") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->fpg_sz);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->fpg_sz);
} else if (strcmp(attr->name, "hw_sector_size") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->csecs);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->csecs);
} else if (strcmp(attr->name, "oob_sector_size") == 0) {/* u32 */
- return scnprintf(page, PAGE_SIZE, "%u\n", id->sos);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->sos);
} else if (strcmp(attr->name, "prog_typ") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tprt);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt);
} else if (strcmp(attr->name, "prog_max") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tprm);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm);
} else if (strcmp(attr->name, "erase_typ") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tbet);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet);
} else if (strcmp(attr->name, "erase_max") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tbem);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem);
} else if (strcmp(attr->name, "multiplane_modes") == 0) {
- return scnprintf(page, PAGE_SIZE, "0x%08x\n", id->mpos);
+ return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mpos);
} else if (strcmp(attr->name, "media_capabilities") == 0) {
- return scnprintf(page, PAGE_SIZE, "0x%08x\n", id->mccap);
+ return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mccap);
} else if (strcmp(attr->name, "max_phys_secs") == 0) {
return scnprintf(page, PAGE_SIZE, "%u\n", NVM_MAX_VLBA);
} else {
- return scnprintf(page,
- PAGE_SIZE,
- "Unhandled attr(%s) in `nvm_dev_attr_show_12`\n",
- attr->name);
+ return scnprintf(page, PAGE_SIZE,
+ "Unhandled attr(%s) in `nvm_dev_attr_show_12`\n",
+ attr->name);
}
}

@@ -952,42 +1011,40 @@ static ssize_t nvm_dev_attr_show_20(struct device *dev,
{
struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
struct nvm_dev *ndev = ns->ndev;
- struct nvm_id *id;
+ struct nvm_geo *geo = &ndev->geo;
struct attribute *attr;

if (!ndev)
return 0;

- id = &ndev->identity;
attr = &dattr->attr;

if (strcmp(attr->name, "groups") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_ch);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
} else if (strcmp(attr->name, "punits") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_lun);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
} else if (strcmp(attr->name, "chunks") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->num_chk);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
} else if (strcmp(attr->name, "clba") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->clba);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->clba);
} else if (strcmp(attr->name, "ws_min") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->ws_min);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_min);
} else if (strcmp(attr->name, "ws_opt") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->ws_opt);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_opt);
} else if (strcmp(attr->name, "mw_cunits") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->mw_cunits);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->mw_cunits);
} else if (strcmp(attr->name, "write_typ") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tprt);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt);
} else if (strcmp(attr->name, "write_max") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tprm);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm);
} else if (strcmp(attr->name, "reset_typ") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tbet);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet);
} else if (strcmp(attr->name, "reset_max") == 0) {
- return scnprintf(page, PAGE_SIZE, "%u\n", id->tbem);
+ return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem);
} else {
- return scnprintf(page,
- PAGE_SIZE,
- "Unhandled attr(%s) in `nvm_dev_attr_show_20`\n",
- attr->name);
+ return scnprintf(page, PAGE_SIZE,
+ "Unhandled attr(%s) in `nvm_dev_attr_show_20`\n",
+ attr->name);
}
}

@@ -1106,10 +1163,13 @@ static const struct attribute_group nvm_dev_attr_group_20 = {

int nvme_nvm_register_sysfs(struct nvme_ns *ns)
{
- if (!ns->ndev)
+ struct nvm_dev *ndev = ns->ndev;
+ struct nvm_geo *geo = &ndev->geo;
+
+ if (!ndev)
return -EINVAL;

- switch (ns->ndev->identity.ver_id) {
+ switch (geo->ver_id) {
case 1:
return sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
&nvm_dev_attr_group_12);
@@ -1123,7 +1183,10 @@ int nvme_nvm_register_sysfs(struct nvme_ns *ns)

void nvme_nvm_unregister_sysfs(struct nvme_ns *ns)
{
- switch (ns->ndev->identity.ver_id) {
+ struct nvm_dev *ndev = ns->ndev;
+ struct nvm_geo *geo = &ndev->geo;
+
+ switch (geo->ver_id) {
case 1:
sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
&nvm_dev_attr_group_12);
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index e55b10573c99..16255fcd5250 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -50,7 +50,7 @@ struct nvm_id;
struct nvm_dev;
struct nvm_tgt_dev;

-typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
+typedef int (nvm_id_fn)(struct nvm_dev *);
typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *);
typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int);
typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
@@ -152,62 +152,48 @@ struct nvm_id_lp_tbl {
struct nvm_id_lp_mlc mlc;
};

-struct nvm_addr_format {
- u8 ch_offset;
+struct nvm_addr_format_12 {
u8 ch_len;
- u8 lun_offset;
u8 lun_len;
- u8 pln_offset;
+ u8 blk_len;
+ u8 pg_len;
u8 pln_len;
+ u8 sect_len;
+
+ u8 ch_offset;
+ u8 lun_offset;
u8 blk_offset;
- u8 blk_len;
u8 pg_offset;
- u8 pg_len;
+ u8 pln_offset;
u8 sect_offset;
- u8 sect_len;
-};
-
-struct nvm_id {
- u8 ver_id;
- u8 vmnt;
- u32 cap;
- u32 dom;
-
- struct nvm_addr_format ppaf;
-
- u8 num_ch;
- u8 num_lun;
- u16 num_chk;
- u16 clba;
- u16 csecs;
- u16 sos;
-
- u32 ws_min;
- u32 ws_opt;
- u32 mw_cunits;

- u32 trdt;
- u32 trdm;
- u32 tprt;
- u32 tprm;
- u32 tbet;
- u32 tbem;
- u32 mpos;
- u32 mccap;
- u16 cpar;
-
- /* calculated values */
- u16 ws_seq;
- u16 ws_per_chk;
-
- /* 1.2 compatibility */
- u8 mtype;
- u8 fmtype;
+ u64 ch_mask;
+ u64 lun_mask;
+ u64 blk_mask;
+ u64 pg_mask;
+ u64 pln_mask;
+ u64 sec_mask;
+};

- u8 num_pln;
- u16 num_pg;
- u16 fpg_sz;
-} __packed;
+struct nvm_addr_format {
+ u8 ch_len;
+ u8 lun_len;
+ u8 chk_len;
+ u8 sec_len;
+ u8 rsv_len[2];
+
+ u8 ch_offset;
+ u8 lun_offset;
+ u8 chk_offset;
+ u8 sec_offset;
+ u8 rsv_off[2];
+
+ u64 ch_mask;
+ u64 lun_mask;
+ u64 chk_mask;
+ u64 sec_mask;
+ u64 rsv_mask[2];
+};

struct nvm_target {
struct list_head list;
@@ -274,36 +260,63 @@ enum {
NVM_BLK_ST_BAD = 0x8, /* Bad block */
};

-
-/* Device generic information */
+/* Instance geometry */
struct nvm_geo {
- /* generic geometry */
+ /* device reported version */
+ u8 ver_id;
+
+ /* instance specific geometry */
int nr_chnls;
- int all_luns; /* across channels */
- int nr_luns; /* per channel */
- int nr_chks; /* per lun */
+ int nr_luns; /* per channel */

- int sec_size;
- int oob_size;
- int mccap;
+ /* calculated values */
+ int all_luns; /* across channels */
+ int all_chunks; /* across channels */

- int sec_per_chk;
- int sec_per_lun;
+ int op; /* over-provision in instance */

- int ws_min;
- int ws_opt;
- int ws_seq;
- int ws_per_chk;
+ sector_t total_secs; /* across channels */

- int op;
+ /* chunk geometry */
+ u32 nr_chks; /* chunks per lun */
+ u32 clba; /* sectors per chunk */
+ u16 csecs; /* sector size */
+ u16 sos; /* out-of-band area size */

- struct nvm_addr_format ppaf;
+ /* device write constrains */
+ u32 ws_min; /* minimum write size */
+ u32 ws_opt; /* optimal write size */
+ u32 mw_cunits; /* distance required for successful read */

- /* Legacy 1.2 specific geometry */
- int plane_mode; /* drive device in single, double or quad mode */
- int nr_planes;
- int sec_per_pg; /* only sectors for a single page */
- int sec_per_pl; /* all sectors across planes */
+ /* device capabilities */
+ u32 mccap;
+
+ /* device timings */
+ u32 trdt; /* Avg. Tread (ns) */
+ u32 trdm; /* Max Tread (ns) */
+ u32 tprt; /* Avg. Tprog (ns) */
+ u32 tprm; /* Max Tprog (ns) */
+ u32 tbet; /* Avg. Terase (ns) */
+ u32 tbem; /* Max Terase (ns) */
+
+ /* generic address format */
+ struct nvm_addr_format addrf;
+
+ /* 1.2 compatibility */
+ u8 vmnt;
+ u32 cap;
+ u32 dom;
+
+ u8 mtype;
+ u8 fmtype;
+
+ u16 cpar;
+ u32 mpos;
+
+ u8 num_pln;
+ u8 plane_mode;
+ u16 num_pg;
+ u16 fpg_sz;
};

/* sub-device structure */
@@ -314,9 +327,6 @@ struct nvm_tgt_dev {
/* Base ppas for target LUNs */
struct ppa_addr *luns;

- sector_t total_secs;
-
- struct nvm_id identity;
struct request_queue *q;

struct nvm_dev *parent;
@@ -331,13 +341,9 @@ struct nvm_dev {
/* Device information */
struct nvm_geo geo;

- unsigned long total_secs;
-
unsigned long *lun_map;
void *dma_pool;

- struct nvm_id identity;
-
/* Backend device */
struct request_queue *q;
char name[DISK_NAME_LEN];
@@ -357,14 +363,16 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
struct ppa_addr r)
{
struct nvm_geo *geo = &tgt_dev->geo;
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&geo->addrf;
struct ppa_addr l;

- l.ppa = ((u64)r.g.blk) << geo->ppaf.blk_offset;
- l.ppa |= ((u64)r.g.pg) << geo->ppaf.pg_offset;
- l.ppa |= ((u64)r.g.sec) << geo->ppaf.sect_offset;
- l.ppa |= ((u64)r.g.pl) << geo->ppaf.pln_offset;
- l.ppa |= ((u64)r.g.lun) << geo->ppaf.lun_offset;
- l.ppa |= ((u64)r.g.ch) << geo->ppaf.ch_offset;
+ l.ppa = ((u64)r.g.ch) << ppaf->ch_offset;
+ l.ppa |= ((u64)r.g.lun) << ppaf->lun_offset;
+ l.ppa |= ((u64)r.g.blk) << ppaf->blk_offset;
+ l.ppa |= ((u64)r.g.pg) << ppaf->pg_offset;
+ l.ppa |= ((u64)r.g.pl) << ppaf->pln_offset;
+ l.ppa |= ((u64)r.g.sec) << ppaf->sect_offset;

return l;
}
@@ -373,24 +381,18 @@ static inline struct ppa_addr dev_to_generic_addr(struct nvm_tgt_dev *tgt_dev,
struct ppa_addr r)
{
struct nvm_geo *geo = &tgt_dev->geo;
+ struct nvm_addr_format_12 *ppaf =
+ (struct nvm_addr_format_12 *)&geo->addrf;
struct ppa_addr l;

l.ppa = 0;
- /*
- * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc.
- */
- l.g.blk = (r.ppa >> geo->ppaf.blk_offset) &
- (((1 << geo->ppaf.blk_len) - 1));
- l.g.pg |= (r.ppa >> geo->ppaf.pg_offset) &
- (((1 << geo->ppaf.pg_len) - 1));
- l.g.sec |= (r.ppa >> geo->ppaf.sect_offset) &
- (((1 << geo->ppaf.sect_len) - 1));
- l.g.pl |= (r.ppa >> geo->ppaf.pln_offset) &
- (((1 << geo->ppaf.pln_len) - 1));
- l.g.lun |= (r.ppa >> geo->ppaf.lun_offset) &
- (((1 << geo->ppaf.lun_len) - 1));
- l.g.ch |= (r.ppa >> geo->ppaf.ch_offset) &
- (((1 << geo->ppaf.ch_len) - 1));
+
+ l.g.ch = (r.ppa & ppaf->ch_mask) >> ppaf->ch_offset;
+ l.g.lun = (r.ppa & ppaf->lun_mask) >> ppaf->lun_offset;
+ l.g.blk = (r.ppa & ppaf->blk_mask) >> ppaf->blk_offset;
+ l.g.pg = (r.ppa & ppaf->pg_mask) >> ppaf->pg_offset;
+ l.g.pl = (r.ppa & ppaf->pln_mask) >> ppaf->pln_offset;
+ l.g.sec = (r.ppa & ppaf->sec_mask) >> ppaf->sect_offset;

return l;
}
--
2.7.4


2018-02-28 17:15:02

by Javier González

[permalink] [raw]
Subject: [PATCH 02/15] lightnvm: add controller capabilities to 2.0

Assign missing mccap value on 2.0 path

Signed-off-by: Javier González <[email protected]>
---
drivers/nvme/host/lightnvm.c | 4 +++-
include/linux/lightnvm.h | 8 +++++---
2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index e276ace28c64..5b2024ebac76 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -318,7 +318,7 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
geo->ws_opt = sec_per_pg;
geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */

- geo->mccap = le32_to_cpu(src->mccap);
+ geo->cap = le32_to_cpu(src->mccap);

geo->trdt = le32_to_cpu(src->trdt);
geo->trdm = le32_to_cpu(src->trdm);
@@ -396,6 +396,8 @@ static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
geo->ws_opt = le32_to_cpu(id->ws_opt);
geo->mw_cunits = le32_to_cpu(id->mw_cunits);

+ geo->cap = le32_to_cpu(id->mccap);
+
geo->trdt = le32_to_cpu(id->trdt);
geo->trdm = le32_to_cpu(id->trdm);
geo->tprt = le32_to_cpu(id->twrt);
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 16255fcd5250..b9f0d2070de9 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -288,8 +288,10 @@ struct nvm_geo {
u32 ws_opt; /* optimal write size */
u32 mw_cunits; /* distance required for successful read */

- /* device capabilities */
- u32 mccap;
+ /* device capabilities. Note that this represents capabilities in 1.2
+ * and media and controller capabilities in 2.0
+ */
+ u32 cap;

/* device timings */
u32 trdt; /* Avg. Tread (ns) */
@@ -304,7 +306,7 @@ struct nvm_geo {

/* 1.2 compatibility */
u8 vmnt;
- u32 cap;
+ u32 mccap;
u32 dom;

u8 mtype;
--
2.7.4


2018-03-01 10:24:04

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 01/15] lightnvm: simplify geometry structure.

On 02/28/2018 04:49 PM, Javier González wrote:
> Currently, the device geometry is stored redundantly in the nvm_id and
> nvm_geo structures at a device level. Moreover, when instantiating
> targets on a specific number of LUNs, these structures are replicated
> and manually modified to fit the instance channel and LUN partitioning.
>
> Instead, create a generic geometry around nvm_geo, which can be used by
> (i) the underlying device to describe the geometry of the whole device,
> and (ii) instances to describe their geometry independently.
>
> Signed-off-by: Javier González <[email protected]>
> ---
> drivers/lightnvm/core.c | 70 +++-----
> drivers/lightnvm/pblk-core.c | 16 +-
> drivers/lightnvm/pblk-gc.c | 2 +-
> drivers/lightnvm/pblk-init.c | 119 +++++++-------
> drivers/lightnvm/pblk-read.c | 2 +-
> drivers/lightnvm/pblk-recovery.c | 14 +-
> drivers/lightnvm/pblk-rl.c | 2 +-
> drivers/lightnvm/pblk-sysfs.c | 39 +++--
> drivers/lightnvm/pblk-write.c | 2 +-
> drivers/lightnvm/pblk.h | 87 +++++-----
> drivers/nvme/host/lightnvm.c | 341 +++++++++++++++++++++++----------------
> include/linux/lightnvm.h | 200 +++++++++++------------
> 12 files changed, 465 insertions(+), 429 deletions(-)
>
> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
> index 19c46ebb1b91..9a417d9cdf0c 100644
> --- a/drivers/lightnvm/core.c
> +++ b/drivers/lightnvm/core.c
> @@ -155,7 +155,7 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
> int blun = lun_begin % dev->geo.nr_luns;
> int lunid = 0;
> int lun_balanced = 1;
> - int prev_nr_luns;
> + int sec_per_lun, prev_nr_luns;
> int i, j;
>
> nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1;
> @@ -215,18 +215,23 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
> if (!tgt_dev)
> goto err_ch;
>
> + /* Inherit device geometry from parent */
> memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo));
> +
> /* Target device only owns a portion of the physical device */
> tgt_dev->geo.nr_chnls = nr_chnls;
> - tgt_dev->geo.all_luns = nr_luns;
> tgt_dev->geo.nr_luns = (lun_balanced) ? prev_nr_luns : -1;
> + tgt_dev->geo.all_luns = nr_luns;
> + tgt_dev->geo.all_chunks = nr_luns * dev->geo.nr_chks;
> +
> tgt_dev->geo.op = op;
> - tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun;
> +
> + sec_per_lun = dev->geo.clba * dev->geo.nr_chks;
> + tgt_dev->geo.total_secs = nr_luns * sec_per_lun;
> +
> tgt_dev->q = dev->q;
> tgt_dev->map = dev_map;
> tgt_dev->luns = luns;
> - memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id));
> -
> tgt_dev->parent = dev;
>
> return tgt_dev;
> @@ -296,8 +301,6 @@ static int __nvm_config_simple(struct nvm_dev *dev,
> static int __nvm_config_extended(struct nvm_dev *dev,
> struct nvm_ioctl_create_extended *e)
> {
> - struct nvm_geo *geo = &dev->geo;
> -
> if (e->lun_begin == 0xFFFF && e->lun_end == 0xFFFF) {
> e->lun_begin = 0;
> e->lun_end = dev->geo.all_luns - 1;
> @@ -311,7 +314,7 @@ static int __nvm_config_extended(struct nvm_dev *dev,
> return -EINVAL;
> }
>
> - return nvm_config_check_luns(geo, e->lun_begin, e->lun_end);
> + return nvm_config_check_luns(&dev->geo, e->lun_begin, e->lun_end);
> }
>
> static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
> @@ -406,7 +409,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
> tqueue->queuedata = targetdata;
>
> blk_queue_max_hw_sectors(tqueue,
> - (dev->geo.sec_size >> 9) * NVM_MAX_VLBA);
> + (dev->geo.csecs >> 9) * NVM_MAX_VLBA);
>
> set_capacity(tdisk, tt->capacity(targetdata));
> add_disk(tdisk);
> @@ -841,40 +844,9 @@ EXPORT_SYMBOL(nvm_get_tgt_bb_tbl);
>
> static int nvm_core_init(struct nvm_dev *dev)
> {
> - struct nvm_id *id = &dev->identity;
> struct nvm_geo *geo = &dev->geo;
> int ret;
>
> - memcpy(&geo->ppaf, &id->ppaf, sizeof(struct nvm_addr_format));
> -
> - if (id->mtype != 0) {
> - pr_err("nvm: memory type not supported\n");
> - return -EINVAL;
> - }
> -
> - /* Whole device values */
> - geo->nr_chnls = id->num_ch;
> - geo->nr_luns = id->num_lun;
> -
> - /* Generic device geometry values */
> - geo->ws_min = id->ws_min;
> - geo->ws_opt = id->ws_opt;
> - geo->ws_seq = id->ws_seq;
> - geo->ws_per_chk = id->ws_per_chk;
> - geo->nr_chks = id->num_chk;
> - geo->mccap = id->mccap;
> -
> - geo->sec_per_chk = id->clba;
> - geo->sec_per_lun = geo->sec_per_chk * geo->nr_chks;
> - geo->all_luns = geo->nr_luns * geo->nr_chnls;
> -
> - /* 1.2 spec device geometry values */
> - geo->plane_mode = 1 << geo->ws_seq;
> - geo->nr_planes = geo->ws_opt / geo->ws_min;
> - geo->sec_per_pg = geo->ws_min;
> - geo->sec_per_pl = geo->sec_per_pg * geo->nr_planes;
> -
> - dev->total_secs = geo->all_luns * geo->sec_per_lun;
> dev->lun_map = kcalloc(BITS_TO_LONGS(geo->all_luns),
> sizeof(unsigned long), GFP_KERNEL);
> if (!dev->lun_map)
> @@ -913,16 +885,14 @@ static int nvm_init(struct nvm_dev *dev)
> struct nvm_geo *geo = &dev->geo;
> int ret = -EINVAL;
>
> - if (dev->ops->identity(dev, &dev->identity)) {
> + if (dev->ops->identity(dev)) {
> pr_err("nvm: device could not be identified\n");
> goto err;
> }
>
> - if (dev->identity.ver_id != 1 && dev->identity.ver_id != 2) {
> - pr_err("nvm: device ver_id %d not supported by kernel.\n",
> - dev->identity.ver_id);
> - goto err;
> - }
> + pr_debug("nvm: ver:%u nvm_vendor:%x\n",
> + geo->ver_id,
> + geo->vmnt);
>
> ret = nvm_core_init(dev);
> if (ret) {
> @@ -930,10 +900,10 @@ static int nvm_init(struct nvm_dev *dev)
> goto err;
> }
>
> - pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
> - dev->name, geo->sec_per_pg, geo->nr_planes,
> - geo->ws_per_chk, geo->nr_chks,
> - geo->all_luns, geo->nr_chnls);
> + pr_info("nvm: registered %s [%u/%u/%u/%u/%u]\n",
> + dev->name, geo->ws_min, geo->ws_opt,
> + geo->nr_chks, geo->all_luns,
> + geo->nr_chnls);
> return 0;
> err:
> pr_err("nvm: failed to initialize nvm\n");
> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
> index 8848443a0721..169589ddd457 100644
> --- a/drivers/lightnvm/pblk-core.c
> +++ b/drivers/lightnvm/pblk-core.c
> @@ -613,7 +613,7 @@ static int pblk_line_submit_emeta_io(struct pblk *pblk, struct pblk_line *line,
> memset(&rqd, 0, sizeof(struct nvm_rq));
>
> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
> - rq_len = rq_ppas * geo->sec_size;
> + rq_len = rq_ppas * geo->csecs;
>
> bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len,
> l_mg->emeta_alloc_type, GFP_KERNEL);
> @@ -722,7 +722,7 @@ u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line)
> if (bit >= lm->blk_per_line)
> return -1;
>
> - return bit * geo->sec_per_pl;
> + return bit * geo->ws_opt;
> }
>
> static int pblk_line_submit_smeta_io(struct pblk *pblk, struct pblk_line *line,
> @@ -1035,19 +1035,19 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
> /* Capture bad block information on line mapping bitmaps */
> while ((bit = find_next_bit(line->blk_bitmap, lm->blk_per_line,
> bit + 1)) < lm->blk_per_line) {
> - off = bit * geo->sec_per_pl;
> + off = bit * geo->ws_opt;
> bitmap_shift_left(l_mg->bb_aux, l_mg->bb_template, off,
> lm->sec_per_line);
> bitmap_or(line->map_bitmap, line->map_bitmap, l_mg->bb_aux,
> lm->sec_per_line);
> - line->sec_in_line -= geo->sec_per_chk;
> + line->sec_in_line -= geo->clba;
> if (bit >= lm->emeta_bb)
> nr_bb++;
> }
>
> /* Mark smeta metadata sectors as bad sectors */
> bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line);
> - off = bit * geo->sec_per_pl;
> + off = bit * geo->ws_opt;
> bitmap_set(line->map_bitmap, off, lm->smeta_sec);
> line->sec_in_line -= lm->smeta_sec;
> line->smeta_ssec = off;
> @@ -1066,10 +1066,10 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
> emeta_secs = lm->emeta_sec[0];
> off = lm->sec_per_line;
> while (emeta_secs) {
> - off -= geo->sec_per_pl;
> + off -= geo->ws_opt;
> if (!test_bit(off, line->invalid_bitmap)) {
> - bitmap_set(line->invalid_bitmap, off, geo->sec_per_pl);
> - emeta_secs -= geo->sec_per_pl;
> + bitmap_set(line->invalid_bitmap, off, geo->ws_opt);
> + emeta_secs -= geo->ws_opt;
> }
> }
>
> diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c
> index 320f99af99e9..6851a5c67189 100644
> --- a/drivers/lightnvm/pblk-gc.c
> +++ b/drivers/lightnvm/pblk-gc.c
> @@ -88,7 +88,7 @@ static void pblk_gc_line_ws(struct work_struct *work)
>
> up(&gc->gc_sem);
>
> - gc_rq->data = vmalloc(gc_rq->nr_secs * geo->sec_size);
> + gc_rq->data = vmalloc(gc_rq->nr_secs * geo->csecs);
> if (!gc_rq->data) {
> pr_err("pblk: could not GC line:%d (%d/%d)\n",
> line->id, *line->vsc, gc_rq->nr_secs);
> diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
> index 25fc70ca07f7..9b5ee05c3028 100644
> --- a/drivers/lightnvm/pblk-init.c
> +++ b/drivers/lightnvm/pblk-init.c
> @@ -146,7 +146,7 @@ static int pblk_rwb_init(struct pblk *pblk)
> return -ENOMEM;
>
> power_size = get_count_order(nr_entries);
> - power_seg_sz = get_count_order(geo->sec_size);
> + power_seg_sz = get_count_order(geo->csecs);
>
> return pblk_rb_init(&pblk->rwb, entries, power_size, power_seg_sz);
> }
> @@ -154,11 +154,11 @@ static int pblk_rwb_init(struct pblk *pblk)
> /* Minimum pages needed within a lun */
> #define ADDR_POOL_SIZE 64
>
> -static int pblk_set_ppaf(struct pblk *pblk)
> +static int pblk_set_addrf_12(struct nvm_geo *geo,
> + struct nvm_addr_format_12 *dst)
> {
> - struct nvm_tgt_dev *dev = pblk->dev;
> - struct nvm_geo *geo = &dev->geo;
> - struct nvm_addr_format ppaf = geo->ppaf;
> + struct nvm_addr_format_12 *src =
> + (struct nvm_addr_format_12 *)&geo->addrf;
> int power_len;
>
> /* Re-calculate channel and lun format to adapt to configuration */
> @@ -167,34 +167,50 @@ static int pblk_set_ppaf(struct pblk *pblk)
> pr_err("pblk: supports only power-of-two channel config.\n");
> return -EINVAL;
> }
> - ppaf.ch_len = power_len;
> + dst->ch_len = power_len;
>
> power_len = get_count_order(geo->nr_luns);
> if (1 << power_len != geo->nr_luns) {
> pr_err("pblk: supports only power-of-two LUN config.\n");
> return -EINVAL;
> }
> - ppaf.lun_len = power_len;
> + dst->lun_len = power_len;
>
> - pblk->ppaf.sec_offset = 0;
> - pblk->ppaf.pln_offset = ppaf.sect_len;
> - pblk->ppaf.ch_offset = pblk->ppaf.pln_offset + ppaf.pln_len;
> - pblk->ppaf.lun_offset = pblk->ppaf.ch_offset + ppaf.ch_len;
> - pblk->ppaf.pg_offset = pblk->ppaf.lun_offset + ppaf.lun_len;
> - pblk->ppaf.blk_offset = pblk->ppaf.pg_offset + ppaf.pg_len;
> - pblk->ppaf.sec_mask = (1ULL << ppaf.sect_len) - 1;
> - pblk->ppaf.pln_mask = ((1ULL << ppaf.pln_len) - 1) <<
> - pblk->ppaf.pln_offset;
> - pblk->ppaf.ch_mask = ((1ULL << ppaf.ch_len) - 1) <<
> - pblk->ppaf.ch_offset;
> - pblk->ppaf.lun_mask = ((1ULL << ppaf.lun_len) - 1) <<
> - pblk->ppaf.lun_offset;
> - pblk->ppaf.pg_mask = ((1ULL << ppaf.pg_len) - 1) <<
> - pblk->ppaf.pg_offset;
> - pblk->ppaf.blk_mask = ((1ULL << ppaf.blk_len) - 1) <<
> - pblk->ppaf.blk_offset;
> + dst->blk_len = src->blk_len;
> + dst->pg_len = src->pg_len;
> + dst->pln_len = src->pln_len;
> + dst->sect_len = src->sect_len;
>
> - pblk->ppaf_bitsize = pblk->ppaf.blk_offset + ppaf.blk_len;
> + dst->sect_offset = 0;
> + dst->pln_offset = dst->sect_len;
> + dst->ch_offset = dst->pln_offset + dst->pln_len;
> + dst->lun_offset = dst->ch_offset + dst->ch_len;
> + dst->pg_offset = dst->lun_offset + dst->lun_len;
> + dst->blk_offset = dst->pg_offset + dst->pg_len;
> +
> + dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
> + dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
> + dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
> + dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
> + dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
> + dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
> +
> + return dst->blk_offset + src->blk_len;
> +}
> +
> +static int pblk_set_ppaf(struct pblk *pblk)
> +{
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> + int mod;
> +
> + div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
> + if (mod) {
> + pr_err("pblk: bad configuration of sectors/pages\n");
> + return -EINVAL;
> + }
> +
> + pblk->ppaf_bitsize = pblk_set_addrf_12(geo, (void *)&pblk->ppaf);
>
> return 0;
> }
> @@ -253,8 +269,7 @@ static int pblk_core_init(struct pblk *pblk)
> struct nvm_tgt_dev *dev = pblk->dev;
> struct nvm_geo *geo = &dev->geo;
>
> - pblk->pgs_in_buffer = NVM_MEM_PAGE_WRITE * geo->sec_per_pg *
> - geo->nr_planes * geo->all_luns;
> + pblk->pgs_in_buffer = geo->mw_cunits * geo->all_luns;
>
> if (pblk_init_global_caches(pblk))
> return -ENOMEM;
> @@ -552,18 +567,18 @@ static unsigned int calc_emeta_len(struct pblk *pblk)
> /* Round to sector size so that lba_list starts on its own sector */
> lm->emeta_sec[1] = DIV_ROUND_UP(
> sizeof(struct line_emeta) + lm->blk_bitmap_len +
> - sizeof(struct wa_counters), geo->sec_size);
> - lm->emeta_len[1] = lm->emeta_sec[1] * geo->sec_size;
> + sizeof(struct wa_counters), geo->csecs);
> + lm->emeta_len[1] = lm->emeta_sec[1] * geo->csecs;
>
> /* Round to sector size so that vsc_list starts on its own sector */
> lm->dsec_per_line = lm->sec_per_line - lm->emeta_sec[0];
> lm->emeta_sec[2] = DIV_ROUND_UP(lm->dsec_per_line * sizeof(u64),
> - geo->sec_size);
> - lm->emeta_len[2] = lm->emeta_sec[2] * geo->sec_size;
> + geo->csecs);
> + lm->emeta_len[2] = lm->emeta_sec[2] * geo->csecs;
>
> lm->emeta_sec[3] = DIV_ROUND_UP(l_mg->nr_lines * sizeof(u32),
> - geo->sec_size);
> - lm->emeta_len[3] = lm->emeta_sec[3] * geo->sec_size;
> + geo->csecs);
> + lm->emeta_len[3] = lm->emeta_sec[3] * geo->csecs;
>
> lm->vsc_list_len = l_mg->nr_lines * sizeof(u32);
>
> @@ -594,13 +609,13 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
> * on user capacity consider only provisioned blocks
> */
> pblk->rl.total_blocks = nr_free_blks;
> - pblk->rl.nr_secs = nr_free_blks * geo->sec_per_chk;
> + pblk->rl.nr_secs = nr_free_blks * geo->clba;
>
> /* Consider sectors used for metadata */
> sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
> - blk_meta = DIV_ROUND_UP(sec_meta, geo->sec_per_chk);
> + blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);
>
> - pblk->capacity = (provisioned - blk_meta) * geo->sec_per_chk;
> + pblk->capacity = (provisioned - blk_meta) * geo->clba;
>
> atomic_set(&pblk->rl.free_blocks, nr_free_blks);
> atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
> @@ -711,10 +726,10 @@ static int pblk_lines_init(struct pblk *pblk)
> void *chunk_log;
> unsigned int smeta_len, emeta_len;
> long nr_bad_blks = 0, nr_free_blks = 0;
> - int bb_distance, max_write_ppas, mod;
> + int bb_distance, max_write_ppas;
> int i, ret;
>
> - pblk->min_write_pgs = geo->sec_per_pl * (geo->sec_size / PAGE_SIZE);
> + pblk->min_write_pgs = geo->ws_opt * (geo->csecs / PAGE_SIZE);
> max_write_ppas = pblk->min_write_pgs * geo->all_luns;
> pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA);
> pblk_set_sec_per_write(pblk, pblk->min_write_pgs);
> @@ -725,19 +740,13 @@ static int pblk_lines_init(struct pblk *pblk)
> return -EINVAL;
> }
>
> - div_u64_rem(geo->sec_per_chk, pblk->min_write_pgs, &mod);
> - if (mod) {
> - pr_err("pblk: bad configuration of sectors/pages\n");
> - return -EINVAL;
> - }
> -
> l_mg->nr_lines = geo->nr_chks;
> l_mg->log_line = l_mg->data_line = NULL;
> l_mg->l_seq_nr = l_mg->d_seq_nr = 0;
> l_mg->nr_free_lines = 0;
> bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES);
>
> - lm->sec_per_line = geo->sec_per_chk * geo->all_luns;
> + lm->sec_per_line = geo->clba * geo->all_luns;
> lm->blk_per_line = geo->all_luns;
> lm->blk_bitmap_len = BITS_TO_LONGS(geo->all_luns) * sizeof(long);
> lm->sec_bitmap_len = BITS_TO_LONGS(lm->sec_per_line) * sizeof(long);
> @@ -751,8 +760,8 @@ static int pblk_lines_init(struct pblk *pblk)
> */
> i = 1;
> add_smeta_page:
> - lm->smeta_sec = i * geo->sec_per_pl;
> - lm->smeta_len = lm->smeta_sec * geo->sec_size;
> + lm->smeta_sec = i * geo->ws_opt;
> + lm->smeta_len = lm->smeta_sec * geo->csecs;
>
> smeta_len = sizeof(struct line_smeta) + lm->lun_bitmap_len;
> if (smeta_len > lm->smeta_len) {
> @@ -765,8 +774,8 @@ static int pblk_lines_init(struct pblk *pblk)
> */
> i = 1;
> add_emeta_page:
> - lm->emeta_sec[0] = i * geo->sec_per_pl;
> - lm->emeta_len[0] = lm->emeta_sec[0] * geo->sec_size;
> + lm->emeta_sec[0] = i * geo->ws_opt;
> + lm->emeta_len[0] = lm->emeta_sec[0] * geo->csecs;
>
> emeta_len = calc_emeta_len(pblk);
> if (emeta_len > lm->emeta_len[0]) {
> @@ -779,7 +788,7 @@ static int pblk_lines_init(struct pblk *pblk)
> lm->min_blk_line = 1;
> if (geo->all_luns > 1)
> lm->min_blk_line += DIV_ROUND_UP(lm->smeta_sec +
> - lm->emeta_sec[0], geo->sec_per_chk);
> + lm->emeta_sec[0], geo->clba);
>
> if (lm->min_blk_line > lm->blk_per_line) {
> pr_err("pblk: config. not supported. Min. LUN in line:%d\n",
> @@ -803,9 +812,9 @@ static int pblk_lines_init(struct pblk *pblk)
> goto fail_free_bb_template;
> }
>
> - bb_distance = (geo->all_luns) * geo->sec_per_pl;
> + bb_distance = (geo->all_luns) * geo->ws_opt;
> for (i = 0; i < lm->sec_per_line; i += bb_distance)
> - bitmap_set(l_mg->bb_template, i, geo->sec_per_pl);
> + bitmap_set(l_mg->bb_template, i, geo->ws_opt);
>
> INIT_LIST_HEAD(&l_mg->free_list);
> INIT_LIST_HEAD(&l_mg->corrupt_list);
> @@ -982,9 +991,9 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
> struct pblk *pblk;
> int ret;
>
> - if (dev->identity.dom & NVM_RSP_L2P) {
> + if (dev->geo.dom & NVM_RSP_L2P) {
> pr_err("pblk: host-side L2P table not supported. (%x)\n",
> - dev->identity.dom);
> + dev->geo.dom);
> return ERR_PTR(-EINVAL);
> }
>
> @@ -1092,7 +1101,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
>
> blk_queue_write_cache(tqueue, true, false);
>
> - tqueue->limits.discard_granularity = geo->sec_per_chk * geo->sec_size;
> + tqueue->limits.discard_granularity = geo->clba * geo->csecs;
> tqueue->limits.discard_alignment = 0;
> blk_queue_max_discard_sectors(tqueue, UINT_MAX >> 9);
> queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, tqueue);
> diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
> index 2f761283f43e..9eee10f69df0 100644
> --- a/drivers/lightnvm/pblk-read.c
> +++ b/drivers/lightnvm/pblk-read.c
> @@ -563,7 +563,7 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
> if (!(gc_rq->secs_to_gc))
> goto out;
>
> - data_len = (gc_rq->secs_to_gc) * geo->sec_size;
> + data_len = (gc_rq->secs_to_gc) * geo->csecs;
> bio = pblk_bio_map_addr(pblk, gc_rq->data, gc_rq->secs_to_gc, data_len,
> PBLK_VMALLOC_META, GFP_KERNEL);
> if (IS_ERR(bio)) {
> diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
> index aaab9a5c17cc..26356429dc72 100644
> --- a/drivers/lightnvm/pblk-recovery.c
> +++ b/drivers/lightnvm/pblk-recovery.c
> @@ -184,7 +184,7 @@ static int pblk_calc_sec_in_line(struct pblk *pblk, struct pblk_line *line)
> int nr_bb = bitmap_weight(line->blk_bitmap, lm->blk_per_line);
>
> return lm->sec_per_line - lm->smeta_sec - lm->emeta_sec[0] -
> - nr_bb * geo->sec_per_chk;
> + nr_bb * geo->clba;
> }
>
> struct pblk_recov_alloc {
> @@ -232,7 +232,7 @@ static int pblk_recov_read_oob(struct pblk *pblk, struct pblk_line *line,
> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
> if (!rq_ppas)
> rq_ppas = pblk->min_write_pgs;
> - rq_len = rq_ppas * geo->sec_size;
> + rq_len = rq_ppas * geo->csecs;
>
> bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
> if (IS_ERR(bio))
> @@ -351,7 +351,7 @@ static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
> if (!pad_rq)
> return -ENOMEM;
>
> - data = vzalloc(pblk->max_write_pgs * geo->sec_size);
> + data = vzalloc(pblk->max_write_pgs * geo->csecs);
> if (!data) {
> ret = -ENOMEM;
> goto free_rq;
> @@ -368,7 +368,7 @@ static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
> goto fail_free_pad;
> }
>
> - rq_len = rq_ppas * geo->sec_size;
> + rq_len = rq_ppas * geo->csecs;
>
> meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list);
> if (!meta_list) {
> @@ -509,7 +509,7 @@ static int pblk_recov_scan_all_oob(struct pblk *pblk, struct pblk_line *line,
> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
> if (!rq_ppas)
> rq_ppas = pblk->min_write_pgs;
> - rq_len = rq_ppas * geo->sec_size;
> + rq_len = rq_ppas * geo->csecs;
>
> bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
> if (IS_ERR(bio))
> @@ -640,7 +640,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
> if (!rq_ppas)
> rq_ppas = pblk->min_write_pgs;
> - rq_len = rq_ppas * geo->sec_size;
> + rq_len = rq_ppas * geo->csecs;
>
> bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
> if (IS_ERR(bio))
> @@ -745,7 +745,7 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line)
> ppa_list = (void *)(meta_list) + pblk_dma_meta_size;
> dma_ppa_list = dma_meta_list + pblk_dma_meta_size;
>
> - data = kcalloc(pblk->max_write_pgs, geo->sec_size, GFP_KERNEL);
> + data = kcalloc(pblk->max_write_pgs, geo->csecs, GFP_KERNEL);
> if (!data) {
> ret = -ENOMEM;
> goto free_meta_list;
> diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c
> index 0d457b162f23..883a7113b19d 100644
> --- a/drivers/lightnvm/pblk-rl.c
> +++ b/drivers/lightnvm/pblk-rl.c
> @@ -200,7 +200,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)
>
> /* Consider sectors used for metadata */
> sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
> - blk_meta = DIV_ROUND_UP(sec_meta, geo->sec_per_chk);
> + blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);
>
> rl->high = pblk->op_blks - blk_meta - lm->blk_per_line;
> rl->high_pw = get_count_order(rl->high);
> diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
> index 1680ce0a828d..33199c6af267 100644
> --- a/drivers/lightnvm/pblk-sysfs.c
> +++ b/drivers/lightnvm/pblk-sysfs.c
> @@ -113,26 +113,31 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
> {
> struct nvm_tgt_dev *dev = pblk->dev;
> struct nvm_geo *geo = &dev->geo;
> + struct nvm_addr_format_12 *ppaf;
> + struct nvm_addr_format_12 *geo_ppaf;
> ssize_t sz = 0;
>
> - sz = snprintf(page, PAGE_SIZE - sz,
> - "g:(b:%d)blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
> - pblk->ppaf_bitsize,
> - pblk->ppaf.blk_offset, geo->ppaf.blk_len,
> - pblk->ppaf.pg_offset, geo->ppaf.pg_len,
> - pblk->ppaf.lun_offset, geo->ppaf.lun_len,
> - pblk->ppaf.ch_offset, geo->ppaf.ch_len,
> - pblk->ppaf.pln_offset, geo->ppaf.pln_len,
> - pblk->ppaf.sec_offset, geo->ppaf.sect_len);
> + ppaf = (struct nvm_addr_format_12 *)&pblk->ppaf;
> + geo_ppaf = (struct nvm_addr_format_12 *)&geo->addrf;
> +
> + sz = snprintf(page, PAGE_SIZE,
> + "pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
> + pblk->ppaf_bitsize,
> + ppaf->ch_offset, ppaf->ch_len,
> + ppaf->lun_offset, ppaf->lun_len,
> + ppaf->blk_offset, ppaf->blk_len,
> + ppaf->pg_offset, ppaf->pg_len,
> + ppaf->pln_offset, ppaf->pln_len,
> + ppaf->sect_offset, ppaf->sect_len);

Is it on purpose here that the code breaks user-space by changing the
sysfs print format?

>
> sz += snprintf(page + sz, PAGE_SIZE - sz,
> - "d:blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
> - geo->ppaf.blk_offset, geo->ppaf.blk_len,
> - geo->ppaf.pg_offset, geo->ppaf.pg_len,
> - geo->ppaf.lun_offset, geo->ppaf.lun_len,
> - geo->ppaf.ch_offset, geo->ppaf.ch_len,
> - geo->ppaf.pln_offset, geo->ppaf.pln_len,
> - geo->ppaf.sect_offset, geo->ppaf.sect_len);
> + "device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
> + geo_ppaf->ch_offset, geo_ppaf->ch_len,
> + geo_ppaf->lun_offset, geo_ppaf->lun_len,
> + geo_ppaf->blk_offset, geo_ppaf->blk_len,
> + geo_ppaf->pg_offset, geo_ppaf->pg_len,
> + geo_ppaf->pln_offset, geo_ppaf->pln_len,
> + geo_ppaf->sect_offset, geo_ppaf->sect_len);

Similarily here.

>
> return sz;
> }
> @@ -288,7 +293,7 @@ static ssize_t pblk_sysfs_lines_info(struct pblk *pblk, char *page)
> "blk_line:%d, sec_line:%d, sec_blk:%d\n",
> lm->blk_per_line,
> lm->sec_per_line,
> - geo->sec_per_chk);
> + geo->clba);
>
> return sz;
> }
> diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c
> index aae86ed60b98..3e6f1ebd743a 100644
> --- a/drivers/lightnvm/pblk-write.c
> +++ b/drivers/lightnvm/pblk-write.c
> @@ -333,7 +333,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line)
> m_ctx = nvm_rq_to_pdu(rqd);
> m_ctx->private = meta_line;
>
> - rq_len = rq_ppas * geo->sec_size;
> + rq_len = rq_ppas * geo->csecs;
> data = ((void *)emeta->buf) + emeta->mem;
>
> bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len,
> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
> index f0309d8172c0..b29c1e6698aa 100644
> --- a/drivers/lightnvm/pblk.h
> +++ b/drivers/lightnvm/pblk.h
> @@ -551,21 +551,6 @@ struct pblk_line_meta {
> unsigned int meta_distance; /* Distance between data and metadata */
> };
>
> -struct pblk_addr_format {
> - u64 ch_mask;
> - u64 lun_mask;
> - u64 pln_mask;
> - u64 blk_mask;
> - u64 pg_mask;
> - u64 sec_mask;
> - u8 ch_offset;
> - u8 lun_offset;
> - u8 pln_offset;
> - u8 blk_offset;
> - u8 pg_offset;
> - u8 sec_offset;
> -};
> -
> enum {
> PBLK_STATE_RUNNING = 0,
> PBLK_STATE_STOPPING = 1,
> @@ -585,8 +570,8 @@ struct pblk {
> struct pblk_line_mgmt l_mg; /* Line management */
> struct pblk_line_meta lm; /* Line metadata */
>
> + struct nvm_addr_format ppaf;
> int ppaf_bitsize;
> - struct pblk_addr_format ppaf;
>
> struct pblk_rb rwb;
>
> @@ -941,14 +926,12 @@ static inline int pblk_line_vsc(struct pblk_line *line)
> return le32_to_cpu(*line->vsc);
> }
>
> -#define NVM_MEM_PAGE_WRITE (8)
> -
> static inline int pblk_pad_distance(struct pblk *pblk)
> {
> struct nvm_tgt_dev *dev = pblk->dev;
> struct nvm_geo *geo = &dev->geo;
>
> - return NVM_MEM_PAGE_WRITE * geo->all_luns * geo->sec_per_pl;
> + return geo->mw_cunits * geo->all_luns * geo->ws_opt;
> }
>
> static inline int pblk_ppa_to_line(struct ppa_addr p)
> @@ -964,15 +947,17 @@ static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
> static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
> u64 line_id)
> {
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&pblk->ppaf;
> struct ppa_addr ppa;
>
> ppa.ppa = 0;
> ppa.g.blk = line_id;
> - ppa.g.pg = (paddr & pblk->ppaf.pg_mask) >> pblk->ppaf.pg_offset;
> - ppa.g.lun = (paddr & pblk->ppaf.lun_mask) >> pblk->ppaf.lun_offset;
> - ppa.g.ch = (paddr & pblk->ppaf.ch_mask) >> pblk->ppaf.ch_offset;
> - ppa.g.pl = (paddr & pblk->ppaf.pln_mask) >> pblk->ppaf.pln_offset;
> - ppa.g.sec = (paddr & pblk->ppaf.sec_mask) >> pblk->ppaf.sec_offset;
> + ppa.g.pg = (paddr & ppaf->pg_mask) >> ppaf->pg_offset;
> + ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
> + ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
> + ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
> + ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sect_offset;
>
> return ppa;
> }
> @@ -980,13 +965,15 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
> static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
> struct ppa_addr p)
> {
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&pblk->ppaf;
> u64 paddr;
>
> - paddr = (u64)p.g.pg << pblk->ppaf.pg_offset;
> - paddr |= (u64)p.g.lun << pblk->ppaf.lun_offset;
> - paddr |= (u64)p.g.ch << pblk->ppaf.ch_offset;
> - paddr |= (u64)p.g.pl << pblk->ppaf.pln_offset;
> - paddr |= (u64)p.g.sec << pblk->ppaf.sec_offset;
> + paddr = (u64)p.g.ch << ppaf->ch_offset;
> + paddr |= (u64)p.g.lun << ppaf->lun_offset;
> + paddr |= (u64)p.g.pg << ppaf->pg_offset;
> + paddr |= (u64)p.g.pl << ppaf->pln_offset;
> + paddr |= (u64)p.g.sec << ppaf->sect_offset;
>
> return paddr;
> }
> @@ -1003,18 +990,15 @@ static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
> ppa64.c.line = ppa32 & ((~0U) >> 1);
> ppa64.c.is_cached = 1;
> } else {
> - ppa64.g.blk = (ppa32 & pblk->ppaf.blk_mask) >>
> - pblk->ppaf.blk_offset;
> - ppa64.g.pg = (ppa32 & pblk->ppaf.pg_mask) >>
> - pblk->ppaf.pg_offset;
> - ppa64.g.lun = (ppa32 & pblk->ppaf.lun_mask) >>
> - pblk->ppaf.lun_offset;
> - ppa64.g.ch = (ppa32 & pblk->ppaf.ch_mask) >>
> - pblk->ppaf.ch_offset;
> - ppa64.g.pl = (ppa32 & pblk->ppaf.pln_mask) >>
> - pblk->ppaf.pln_offset;
> - ppa64.g.sec = (ppa32 & pblk->ppaf.sec_mask) >>
> - pblk->ppaf.sec_offset;
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&pblk->ppaf;
> +
> + ppa64.g.ch = (ppa32 & ppaf->ch_mask) >> ppaf->ch_offset;
> + ppa64.g.lun = (ppa32 & ppaf->lun_mask) >> ppaf->lun_offset;
> + ppa64.g.blk = (ppa32 & ppaf->blk_mask) >> ppaf->blk_offset;
> + ppa64.g.pg = (ppa32 & ppaf->pg_mask) >> ppaf->pg_offset;
> + ppa64.g.pl = (ppa32 & ppaf->pln_mask) >> ppaf->pln_offset;
> + ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> ppaf->sect_offset;
> }
>
> return ppa64;
> @@ -1030,12 +1014,15 @@ static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
> ppa32 |= ppa64.c.line;
> ppa32 |= 1U << 31;
> } else {
> - ppa32 |= ppa64.g.blk << pblk->ppaf.blk_offset;
> - ppa32 |= ppa64.g.pg << pblk->ppaf.pg_offset;
> - ppa32 |= ppa64.g.lun << pblk->ppaf.lun_offset;
> - ppa32 |= ppa64.g.ch << pblk->ppaf.ch_offset;
> - ppa32 |= ppa64.g.pl << pblk->ppaf.pln_offset;
> - ppa32 |= ppa64.g.sec << pblk->ppaf.sec_offset;
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&pblk->ppaf;
> +
> + ppa32 |= ppa64.g.ch << ppaf->ch_offset;
> + ppa32 |= ppa64.g.lun << ppaf->lun_offset;
> + ppa32 |= ppa64.g.blk << ppaf->blk_offset;
> + ppa32 |= ppa64.g.pg << ppaf->pg_offset;
> + ppa32 |= ppa64.g.pl << ppaf->pln_offset;
> + ppa32 |= ppa64.g.sec << ppaf->sect_offset;
> }
>
> return ppa32;
> @@ -1229,10 +1216,10 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev,
> if (!ppa->c.is_cached &&
> ppa->g.ch < geo->nr_chnls &&
> ppa->g.lun < geo->nr_luns &&
> - ppa->g.pl < geo->nr_planes &&
> + ppa->g.pl < geo->num_pln &&
> ppa->g.blk < geo->nr_chks &&
> - ppa->g.pg < geo->ws_per_chk &&
> - ppa->g.sec < geo->sec_per_pg)
> + ppa->g.pg < geo->num_pg &&
> + ppa->g.sec < geo->ws_min)
> continue;
>
> print_ppa(ppa, "boundary", i);
> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
> index 839c0b96466a..e276ace28c64 100644
> --- a/drivers/nvme/host/lightnvm.c
> +++ b/drivers/nvme/host/lightnvm.c
> @@ -152,8 +152,8 @@ struct nvme_nvm_id12_addrf {
> __u8 blk_len;
> __u8 pg_offset;
> __u8 pg_len;
> - __u8 sect_offset;
> - __u8 sect_len;
> + __u8 sec_offset;
> + __u8 sec_len;
> __u8 res[4];
> } __packed;
>
> @@ -254,106 +254,161 @@ static inline void _nvme_nvm_check_size(void)
> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
> }
>
> -static int init_grp(struct nvm_id *nvm_id, struct nvme_nvm_id12 *id12)
> +static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
> + struct nvme_nvm_id12_addrf *src)
> +{
> + dst->ch_len = src->ch_len;
> + dst->lun_len = src->lun_len;
> + dst->blk_len = src->blk_len;
> + dst->pg_len = src->pg_len;
> + dst->pln_len = src->pln_len;
> + dst->sect_len = src->sec_len;
> +
> + dst->ch_offset = src->ch_offset;
> + dst->lun_offset = src->lun_offset;
> + dst->blk_offset = src->blk_offset;
> + dst->pg_offset = src->pg_offset;
> + dst->pln_offset = src->pln_offset;
> + dst->sect_offset = src->sec_offset;
> +
> + dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
> + dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
> + dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
> + dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
> + dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
> + dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
> +}
> +
> +static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
> + struct nvm_geo *geo)
> {
> struct nvme_nvm_id12_grp *src;
> int sec_per_pg, sec_per_pl, pg_per_blk;
>
> - if (id12->cgrps != 1)
> + if (id->cgrps != 1)
> return -EINVAL;
>
> - src = &id12->grp;
> + src = &id->grp;
>
> - nvm_id->mtype = src->mtype;
> - nvm_id->fmtype = src->fmtype;
> + if (src->mtype != 0) {
> + pr_err("nvm: memory type not supported\n");
> + return -EINVAL;
> + }
> +
> + geo->ver_id = id->ver_id;
> +
> + geo->nr_chnls = src->num_ch;
> + geo->nr_luns = src->num_lun;
> + geo->all_luns = geo->nr_chnls * geo->nr_luns;
>
> - nvm_id->num_ch = src->num_ch;
> - nvm_id->num_lun = src->num_lun;
> + geo->nr_chks = le16_to_cpu(src->num_chk);
>
> - nvm_id->num_chk = le16_to_cpu(src->num_chk);
> - nvm_id->csecs = le16_to_cpu(src->csecs);
> - nvm_id->sos = le16_to_cpu(src->sos);
> + geo->csecs = le16_to_cpu(src->csecs);
> + geo->sos = le16_to_cpu(src->sos);
>
> pg_per_blk = le16_to_cpu(src->num_pg);
> - sec_per_pg = le16_to_cpu(src->fpg_sz) / nvm_id->csecs;
> + sec_per_pg = le16_to_cpu(src->fpg_sz) / geo->csecs;
> sec_per_pl = sec_per_pg * src->num_pln;
> - nvm_id->clba = sec_per_pl * pg_per_blk;
> - nvm_id->ws_per_chk = pg_per_blk;
> -
> - nvm_id->mpos = le32_to_cpu(src->mpos);
> - nvm_id->cpar = le16_to_cpu(src->cpar);
> - nvm_id->mccap = le32_to_cpu(src->mccap);
> -
> - nvm_id->ws_opt = nvm_id->ws_min = sec_per_pg;
> - nvm_id->ws_seq = NVM_IO_SNGL_ACCESS;
> -
> - if (nvm_id->mpos & 0x020202) {
> - nvm_id->ws_seq = NVM_IO_DUAL_ACCESS;
> - nvm_id->ws_opt <<= 1;
> - } else if (nvm_id->mpos & 0x040404) {
> - nvm_id->ws_seq = NVM_IO_QUAD_ACCESS;
> - nvm_id->ws_opt <<= 2;
> + geo->clba = sec_per_pl * pg_per_blk;
> +
> + geo->all_chunks = geo->all_luns * geo->nr_chks;
> + geo->total_secs = geo->clba * geo->all_chunks;
> +
> + geo->ws_min = sec_per_pg;
> + geo->ws_opt = sec_per_pg;
> + geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */
> +
> + geo->mccap = le32_to_cpu(src->mccap);
> +
> + geo->trdt = le32_to_cpu(src->trdt);
> + geo->trdm = le32_to_cpu(src->trdm);
> + geo->tprt = le32_to_cpu(src->tprt);
> + geo->tprm = le32_to_cpu(src->tprm);
> + geo->tbet = le32_to_cpu(src->tbet);
> + geo->tbem = le32_to_cpu(src->tbem);
> +
> + /* 1.2 compatibility */
> + geo->vmnt = id->vmnt;
> + geo->cap = le32_to_cpu(id->cap);
> + geo->dom = le32_to_cpu(id->dom);
> +
> + geo->mtype = src->mtype;
> + geo->fmtype = src->fmtype;
> +
> + geo->cpar = le16_to_cpu(src->cpar);
> + geo->mpos = le32_to_cpu(src->mpos);
> +
> + geo->plane_mode = NVM_PLANE_SINGLE;
> +
> + if (geo->mpos & 0x020202) {
> + geo->plane_mode = NVM_PLANE_DOUBLE;
> + geo->ws_opt <<= 1;
> + } else if (geo->mpos & 0x040404) {
> + geo->plane_mode = NVM_PLANE_QUAD;
> + geo->ws_opt <<= 2;
> }
>
> - nvm_id->trdt = le32_to_cpu(src->trdt);
> - nvm_id->trdm = le32_to_cpu(src->trdm);
> - nvm_id->tprt = le32_to_cpu(src->tprt);
> - nvm_id->tprm = le32_to_cpu(src->tprm);
> - nvm_id->tbet = le32_to_cpu(src->tbet);
> - nvm_id->tbem = le32_to_cpu(src->tbem);
> -
> - /* 1.2 compatibility */
> - nvm_id->num_pln = src->num_pln;
> - nvm_id->num_pg = le16_to_cpu(src->num_pg);
> - nvm_id->fpg_sz = le16_to_cpu(src->fpg_sz);
> + geo->num_pln = src->num_pln;
> + geo->num_pg = le16_to_cpu(src->num_pg);
> + geo->fpg_sz = le16_to_cpu(src->fpg_sz);
> +
> + nvme_nvm_set_addr_12((struct nvm_addr_format_12 *)&geo->addrf,
> + &id->ppaf);
>
> return 0;
> }
>
> -static int nvme_nvm_setup_12(struct nvm_dev *nvmdev, struct nvm_id *nvm_id,
> - struct nvme_nvm_id12 *id)
> +static void nvme_nvm_set_addr_20(struct nvm_addr_format *dst,
> + struct nvme_nvm_id20_addrf *src)
> {
> - nvm_id->ver_id = id->ver_id;
> - nvm_id->vmnt = id->vmnt;
> - nvm_id->cap = le32_to_cpu(id->cap);
> - nvm_id->dom = le32_to_cpu(id->dom);
> - memcpy(&nvm_id->ppaf, &id->ppaf,
> - sizeof(struct nvm_addr_format));
> -
> - return init_grp(nvm_id, id);
> + dst->ch_len = src->grp_len;
> + dst->lun_len = src->pu_len;
> + dst->chk_len = src->chk_len;
> + dst->sec_len = src->lba_len;
> +
> + dst->sec_offset = 0;
> + dst->chk_offset = dst->sec_len;
> + dst->lun_offset = dst->chk_offset + dst->chk_len;
> + dst->ch_offset = dst->lun_offset + dst->lun_len;
> +
> + dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
> + dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
> + dst->chk_mask = ((1ULL << dst->chk_len) - 1) << dst->chk_offset;
> + dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset;
> }
>
> -static int nvme_nvm_setup_20(struct nvm_dev *nvmdev, struct nvm_id *nvm_id,
> - struct nvme_nvm_id20 *id)
> +static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
> + struct nvm_geo *geo)
> {
> - nvm_id->ver_id = id->mjr;
> + geo->ver_id = id->mjr;
> +
> + geo->nr_chnls = le16_to_cpu(id->num_grp);
> + geo->nr_luns = le16_to_cpu(id->num_pu);
> + geo->all_luns = geo->nr_chnls * geo->nr_luns;
>
> - nvm_id->num_ch = le16_to_cpu(id->num_grp);
> - nvm_id->num_lun = le16_to_cpu(id->num_pu);
> - nvm_id->num_chk = le32_to_cpu(id->num_chk);
> - nvm_id->clba = le32_to_cpu(id->clba);
> + geo->nr_chks = le32_to_cpu(id->num_chk);
> + geo->clba = le32_to_cpu(id->clba);
>
> - nvm_id->ws_min = le32_to_cpu(id->ws_min);
> - nvm_id->ws_opt = le32_to_cpu(id->ws_opt);
> - nvm_id->mw_cunits = le32_to_cpu(id->mw_cunits);
> + geo->all_chunks = geo->all_luns * geo->nr_chks;
> + geo->total_secs = geo->clba * geo->all_chunks;
>
> - nvm_id->trdt = le32_to_cpu(id->trdt);
> - nvm_id->trdm = le32_to_cpu(id->trdm);
> - nvm_id->tprt = le32_to_cpu(id->twrt);
> - nvm_id->tprm = le32_to_cpu(id->twrm);
> - nvm_id->tbet = le32_to_cpu(id->tcrst);
> - nvm_id->tbem = le32_to_cpu(id->tcrsm);
> + geo->ws_min = le32_to_cpu(id->ws_min);
> + geo->ws_opt = le32_to_cpu(id->ws_opt);
> + geo->mw_cunits = le32_to_cpu(id->mw_cunits);
>
> - /* calculated values */
> - nvm_id->ws_per_chk = nvm_id->clba / nvm_id->ws_min;
> + geo->trdt = le32_to_cpu(id->trdt);
> + geo->trdm = le32_to_cpu(id->trdm);
> + geo->tprt = le32_to_cpu(id->twrt);
> + geo->tprm = le32_to_cpu(id->twrm);
> + geo->tbet = le32_to_cpu(id->tcrst);
> + geo->tbem = le32_to_cpu(id->tcrsm);
>
> - /* 1.2 compatibility */
> - nvm_id->ws_seq = NVM_IO_SNGL_ACCESS;
> + nvme_nvm_set_addr_20(&geo->addrf, &id->lbaf);
>
> return 0;
> }
>
> -static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
> +static int nvme_nvm_identity(struct nvm_dev *nvmdev)
> {
> struct nvme_ns *ns = nvmdev->q->queuedata;
> struct nvme_nvm_id12 *id;
> @@ -380,18 +435,18 @@ static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
> */
> switch (id->ver_id) {
> case 1:
> - ret = nvme_nvm_setup_12(nvmdev, nvm_id, id);
> + ret = nvme_nvm_setup_12(id, &nvmdev->geo);
> break;
> case 2:
> - ret = nvme_nvm_setup_20(nvmdev, nvm_id,
> - (struct nvme_nvm_id20 *)id);
> + ret = nvme_nvm_setup_20((struct nvme_nvm_id20 *)id,
> + &nvmdev->geo);
> break;
> default:
> - dev_err(ns->ctrl->device,
> - "OCSSD revision not supported (%d)\n",
> - nvm_id->ver_id);
> + dev_err(ns->ctrl->device, "OCSSD revision not supported (%d)\n",
> + id->ver_id);
> ret = -EINVAL;
> }
> +
> out:
> kfree(id);
> return ret;
> @@ -406,7 +461,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
> struct nvme_ctrl *ctrl = ns->ctrl;
> struct nvme_nvm_command c = {};
> struct nvme_nvm_bb_tbl *bb_tbl;
> - int nr_blks = geo->nr_chks * geo->plane_mode;
> + int nr_blks = geo->nr_chks * geo->num_pln;
> int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blks;
> int ret = 0;
>
> @@ -447,7 +502,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
> goto out;
> }
>
> - memcpy(blks, bb_tbl->blk, geo->nr_chks * geo->plane_mode);
> + memcpy(blks, bb_tbl->blk, geo->nr_chks * geo->num_pln);
> out:
> kfree(bb_tbl);
> return ret;
> @@ -815,9 +870,10 @@ int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg)
> void nvme_nvm_update_nvm_info(struct nvme_ns *ns)
> {
> struct nvm_dev *ndev = ns->ndev;
> + struct nvm_geo *geo = &ndev->geo;
>
> - ndev->identity.csecs = ndev->geo.sec_size = 1 << ns->lba_shift;
> - ndev->identity.sos = ndev->geo.oob_size = ns->ms;
> + geo->csecs = 1 << ns->lba_shift;
> + geo->sos = ns->ms;
> }
>
> int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node)
> @@ -850,23 +906,22 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
> {
> struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
> struct nvm_dev *ndev = ns->ndev;
> - struct nvm_id *id;
> + struct nvm_geo *geo = &ndev->geo;
> struct attribute *attr;
>
> if (!ndev)
> return 0;
>
> - id = &ndev->identity;
> attr = &dattr->attr;
>
> if (strcmp(attr->name, "version") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->ver_id);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->ver_id);
> } else if (strcmp(attr->name, "capabilities") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->cap);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->cap);
> } else if (strcmp(attr->name, "read_typ") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->trdt);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdt);
> } else if (strcmp(attr->name, "read_max") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->trdm);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdm);
> } else {
> return scnprintf(page,
> PAGE_SIZE,
> @@ -875,75 +930,79 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
> }
> }
>
> +static ssize_t nvm_dev_attr_show_ppaf(struct nvm_addr_format_12 *ppaf,
> + char *page)
> +{
> + return scnprintf(page, PAGE_SIZE,
> + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> + ppaf->ch_offset, ppaf->ch_len,
> + ppaf->lun_offset, ppaf->lun_len,
> + ppaf->pln_offset, ppaf->pln_len,
> + ppaf->blk_offset, ppaf->blk_len,
> + ppaf->pg_offset, ppaf->pg_len,
> + ppaf->sect_offset, ppaf->sect_len);
> +}
> +
> static ssize_t nvm_dev_attr_show_12(struct device *dev,
> struct device_attribute *dattr, char *page)
> {
> struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
> struct nvm_dev *ndev = ns->ndev;
> - struct nvm_id *id;
> + struct nvm_geo *geo = &ndev->geo;
> struct attribute *attr;
>
> if (!ndev)
> return 0;
>
> - id = &ndev->identity;
> attr = &dattr->attr;
>
> if (strcmp(attr->name, "vendor_opcode") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->vmnt);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->vmnt);
> } else if (strcmp(attr->name, "device_mode") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->dom);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->dom);
> /* kept for compatibility */
> } else if (strcmp(attr->name, "media_manager") == 0) {
> return scnprintf(page, PAGE_SIZE, "%s\n", "gennvm");
> } else if (strcmp(attr->name, "ppa_format") == 0) {
> - return scnprintf(page, PAGE_SIZE,
> - "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> - id->ppaf.ch_offset, id->ppaf.ch_len,
> - id->ppaf.lun_offset, id->ppaf.lun_len,
> - id->ppaf.pln_offset, id->ppaf.pln_len,
> - id->ppaf.blk_offset, id->ppaf.blk_len,
> - id->ppaf.pg_offset, id->ppaf.pg_len,
> - id->ppaf.sect_offset, id->ppaf.sect_len);
> + return nvm_dev_attr_show_ppaf((void *)&geo->addrf, page);

Why do the code here cast to void *, and not to the address format data
structure?

Have you thought about doing the cast directly here, instead of making a
function for it?

> } else if (strcmp(attr->name, "media_type") == 0) { /* u8 */
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->mtype);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->mtype);
> } else if (strcmp(attr->name, "flash_media_type") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->fmtype);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->fmtype);
> } else if (strcmp(attr->name, "num_channels") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_ch);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
> } else if (strcmp(attr->name, "num_luns") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_lun);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
> } else if (strcmp(attr->name, "num_planes") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_pln);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pln);
> } else if (strcmp(attr->name, "num_blocks") == 0) { /* u16 */
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_chk);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
> } else if (strcmp(attr->name, "num_pages") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_pg);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pg);
> } else if (strcmp(attr->name, "page_size") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->fpg_sz);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->fpg_sz);
> } else if (strcmp(attr->name, "hw_sector_size") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->csecs);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->csecs);
> } else if (strcmp(attr->name, "oob_sector_size") == 0) {/* u32 */
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->sos);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->sos);
> } else if (strcmp(attr->name, "prog_typ") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprt);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt);
> } else if (strcmp(attr->name, "prog_max") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprm);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm);
> } else if (strcmp(attr->name, "erase_typ") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbet);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet);
> } else if (strcmp(attr->name, "erase_max") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbem);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem);
> } else if (strcmp(attr->name, "multiplane_modes") == 0) {
> - return scnprintf(page, PAGE_SIZE, "0x%08x\n", id->mpos);
> + return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mpos);
> } else if (strcmp(attr->name, "media_capabilities") == 0) {
> - return scnprintf(page, PAGE_SIZE, "0x%08x\n", id->mccap);
> + return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mccap);
> } else if (strcmp(attr->name, "max_phys_secs") == 0) {
> return scnprintf(page, PAGE_SIZE, "%u\n", NVM_MAX_VLBA);
> } else {
> - return scnprintf(page,
> - PAGE_SIZE,
> - "Unhandled attr(%s) in `nvm_dev_attr_show_12`\n",
> - attr->name);
> + return scnprintf(page, PAGE_SIZE,
> + "Unhandled attr(%s) in `nvm_dev_attr_show_12`\n",
> + attr->name);
> }
> }
>
> @@ -952,42 +1011,40 @@ static ssize_t nvm_dev_attr_show_20(struct device *dev,
> {
> struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
> struct nvm_dev *ndev = ns->ndev;
> - struct nvm_id *id;
> + struct nvm_geo *geo = &ndev->geo;
> struct attribute *attr;
>
> if (!ndev)
> return 0;
>
> - id = &ndev->identity;
> attr = &dattr->attr;
>
> if (strcmp(attr->name, "groups") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_ch);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
> } else if (strcmp(attr->name, "punits") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_lun);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
> } else if (strcmp(attr->name, "chunks") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_chk);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
> } else if (strcmp(attr->name, "clba") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->clba);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->clba);
> } else if (strcmp(attr->name, "ws_min") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->ws_min);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_min);
> } else if (strcmp(attr->name, "ws_opt") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->ws_opt);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_opt);
> } else if (strcmp(attr->name, "mw_cunits") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->mw_cunits);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->mw_cunits);
> } else if (strcmp(attr->name, "write_typ") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprt);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt);
> } else if (strcmp(attr->name, "write_max") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprm);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm);
> } else if (strcmp(attr->name, "reset_typ") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbet);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet);
> } else if (strcmp(attr->name, "reset_max") == 0) {
> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbem);
> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem);
> } else {
> - return scnprintf(page,
> - PAGE_SIZE,
> - "Unhandled attr(%s) in `nvm_dev_attr_show_20`\n",
> - attr->name);
> + return scnprintf(page, PAGE_SIZE,
> + "Unhandled attr(%s) in `nvm_dev_attr_show_20`\n",
> + attr->name);
> }
> }
>
> @@ -1106,10 +1163,13 @@ static const struct attribute_group nvm_dev_attr_group_20 = {
>
> int nvme_nvm_register_sysfs(struct nvme_ns *ns)
> {
> - if (!ns->ndev)
> + struct nvm_dev *ndev = ns->ndev;
> + struct nvm_geo *geo = &ndev->geo;
> +
> + if (!ndev)
> return -EINVAL;
>
> - switch (ns->ndev->identity.ver_id) {
> + switch (geo->ver_id) {
> case 1:
> return sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
> &nvm_dev_attr_group_12);
> @@ -1123,7 +1183,10 @@ int nvme_nvm_register_sysfs(struct nvme_ns *ns)
>
> void nvme_nvm_unregister_sysfs(struct nvme_ns *ns)
> {
> - switch (ns->ndev->identity.ver_id) {
> + struct nvm_dev *ndev = ns->ndev;
> + struct nvm_geo *geo = &ndev->geo;
> +
> + switch (geo->ver_id) {
> case 1:
> sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
> &nvm_dev_attr_group_12);
> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
> index e55b10573c99..16255fcd5250 100644
> --- a/include/linux/lightnvm.h
> +++ b/include/linux/lightnvm.h
> @@ -50,7 +50,7 @@ struct nvm_id;
> struct nvm_dev;
> struct nvm_tgt_dev;
>
> -typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
> +typedef int (nvm_id_fn)(struct nvm_dev *);
> typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *);
> typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int);
> typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
> @@ -152,62 +152,48 @@ struct nvm_id_lp_tbl {
> struct nvm_id_lp_mlc mlc;
> };
>
> -struct nvm_addr_format {
> - u8 ch_offset;
> +struct nvm_addr_format_12 {

I can see in a couple of places a statement has to be over two lines due
to the length of writing out nvm_addr_format_12, would it make sense to
shorthand it to nvm_addrf_12?

> u8 ch_len;
> - u8 lun_offset;
> u8 lun_len;
> - u8 pln_offset;
> + u8 blk_len;
> + u8 pg_len;
> u8 pln_len;
> + u8 sect_len;
> +
> + u8 ch_offset;
> + u8 lun_offset;
> u8 blk_offset;
> - u8 blk_len;
> u8 pg_offset;
> - u8 pg_len;
> + u8 pln_offset;
> u8 sect_offset;
> - u8 sect_len;
> -};
> -
> -struct nvm_id {
> - u8 ver_id;
> - u8 vmnt;
> - u32 cap;
> - u32 dom;
> -
> - struct nvm_addr_format ppaf;
> -
> - u8 num_ch;
> - u8 num_lun;
> - u16 num_chk;
> - u16 clba;
> - u16 csecs;
> - u16 sos;
> -
> - u32 ws_min;
> - u32 ws_opt;
> - u32 mw_cunits;
>
> - u32 trdt;
> - u32 trdm;
> - u32 tprt;
> - u32 tprm;
> - u32 tbet;
> - u32 tbem;
> - u32 mpos;
> - u32 mccap;
> - u16 cpar;
> -
> - /* calculated values */
> - u16 ws_seq;
> - u16 ws_per_chk;
> -
> - /* 1.2 compatibility */
> - u8 mtype;
> - u8 fmtype;
> + u64 ch_mask;
> + u64 lun_mask;
> + u64 blk_mask;
> + u64 pg_mask;
> + u64 pln_mask;
> + u64 sec_mask;
> +};
>
> - u8 num_pln;
> - u16 num_pg;
> - u16 fpg_sz;
> -} __packed;
> +struct nvm_addr_format {
> + u8 ch_len;
> + u8 lun_len;
> + u8 chk_len;
> + u8 sec_len;
> + u8 rsv_len[2];
> +
> + u8 ch_offset;
> + u8 lun_offset;
> + u8 chk_offset;
> + u8 sec_offset;
> + u8 rsv_off[2];
> +
> + u64 ch_mask;
> + u64 lun_mask;
> + u64 chk_mask;
> + u64 sec_mask;
> + u64 rsv_mask[2];
> +};
>
> struct nvm_target {
> struct list_head list;
> @@ -274,36 +260,63 @@ enum {
> NVM_BLK_ST_BAD = 0x8, /* Bad block */
> };
>
> -
> -/* Device generic information */
> +/* Instance geometry */
> struct nvm_geo {
> - /* generic geometry */
> + /* device reported version */
> + u8 ver_id;
> +
> + /* instance specific geometry */
> int nr_chnls;
> - int all_luns; /* across channels */
> - int nr_luns; /* per channel */
> - int nr_chks; /* per lun */
> + int nr_luns; /* per channel */
>
> - int sec_size;
> - int oob_size;
> - int mccap;
> + /* calculated values */
> + int all_luns; /* across channels */
> + int all_chunks; /* across channels */
>
> - int sec_per_chk;
> - int sec_per_lun;
> + int op; /* over-provision in instance */
>
> - int ws_min;
> - int ws_opt;
> - int ws_seq;
> - int ws_per_chk;
> + sector_t total_secs; /* across channels */
>
> - int op;
> + /* chunk geometry */
> + u32 nr_chks; /* chunks per lun */
> + u32 clba; /* sectors per chunk */
> + u16 csecs; /* sector size */
> + u16 sos; /* out-of-band area size */
>
> - struct nvm_addr_format ppaf;
> + /* device write constrains */
> + u32 ws_min; /* minimum write size */
> + u32 ws_opt; /* optimal write size */
> + u32 mw_cunits; /* distance required for successful read */
>
> - /* Legacy 1.2 specific geometry */
> - int plane_mode; /* drive device in single, double or quad mode */
> - int nr_planes;
> - int sec_per_pg; /* only sectors for a single page */
> - int sec_per_pl; /* all sectors across planes */
> + /* device capabilities */
> + u32 mccap;
> +
> + /* device timings */
> + u32 trdt; /* Avg. Tread (ns) */
> + u32 trdm; /* Max Tread (ns) */
> + u32 tprt; /* Avg. Tprog (ns) */
> + u32 tprm; /* Max Tprog (ns) */
> + u32 tbet; /* Avg. Terase (ns) */
> + u32 tbem; /* Max Terase (ns) */
> +
> + /* generic address format */
> + struct nvm_addr_format addrf;
> +
> + /* 1.2 compatibility */
> + u8 vmnt;
> + u32 cap;
> + u32 dom;
> +
> + u8 mtype;
> + u8 fmtype;
> +
> + u16 cpar;
> + u32 mpos;
> +
> + u8 num_pln;
> + u8 plane_mode;
> + u16 num_pg;
> + u16 fpg_sz;
> };
>
> /* sub-device structure */
> @@ -314,9 +327,6 @@ struct nvm_tgt_dev {
> /* Base ppas for target LUNs */
> struct ppa_addr *luns;
>
> - sector_t total_secs;
> -
> - struct nvm_id identity;
> struct request_queue *q;
>
> struct nvm_dev *parent;
> @@ -331,13 +341,9 @@ struct nvm_dev {
> /* Device information */
> struct nvm_geo geo;
>
> - unsigned long total_secs;
> -
> unsigned long *lun_map;
> void *dma_pool;
>
> - struct nvm_id identity;
> -
> /* Backend device */
> struct request_queue *q;
> char name[DISK_NAME_LEN];
> @@ -357,14 +363,16 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
> struct ppa_addr r)
> {
> struct nvm_geo *geo = &tgt_dev->geo;
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&geo->addrf;
> struct ppa_addr l;
>
> - l.ppa = ((u64)r.g.blk) << geo->ppaf.blk_offset;
> - l.ppa |= ((u64)r.g.pg) << geo->ppaf.pg_offset;
> - l.ppa |= ((u64)r.g.sec) << geo->ppaf.sect_offset;
> - l.ppa |= ((u64)r.g.pl) << geo->ppaf.pln_offset;
> - l.ppa |= ((u64)r.g.lun) << geo->ppaf.lun_offset;
> - l.ppa |= ((u64)r.g.ch) << geo->ppaf.ch_offset;
> + l.ppa = ((u64)r.g.ch) << ppaf->ch_offset;
> + l.ppa |= ((u64)r.g.lun) << ppaf->lun_offset;
> + l.ppa |= ((u64)r.g.blk) << ppaf->blk_offset;
> + l.ppa |= ((u64)r.g.pg) << ppaf->pg_offset;
> + l.ppa |= ((u64)r.g.pl) << ppaf->pln_offset;
> + l.ppa |= ((u64)r.g.sec) << ppaf->sect_offset;
>
> return l;
> }
> @@ -373,24 +381,18 @@ static inline struct ppa_addr dev_to_generic_addr(struct nvm_tgt_dev *tgt_dev,
> struct ppa_addr r)
> {
> struct nvm_geo *geo = &tgt_dev->geo;
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&geo->addrf;
> struct ppa_addr l;
>
> l.ppa = 0;
> - /*
> - * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc.
> - */
> - l.g.blk = (r.ppa >> geo->ppaf.blk_offset) &
> - (((1 << geo->ppaf.blk_len) - 1));
> - l.g.pg |= (r.ppa >> geo->ppaf.pg_offset) &
> - (((1 << geo->ppaf.pg_len) - 1));
> - l.g.sec |= (r.ppa >> geo->ppaf.sect_offset) &
> - (((1 << geo->ppaf.sect_len) - 1));
> - l.g.pl |= (r.ppa >> geo->ppaf.pln_offset) &
> - (((1 << geo->ppaf.pln_len) - 1));
> - l.g.lun |= (r.ppa >> geo->ppaf.lun_offset) &
> - (((1 << geo->ppaf.lun_len) - 1));
> - l.g.ch |= (r.ppa >> geo->ppaf.ch_offset) &
> - (((1 << geo->ppaf.ch_len) - 1));
> +
> + l.g.ch = (r.ppa & ppaf->ch_mask) >> ppaf->ch_offset;
> + l.g.lun = (r.ppa & ppaf->lun_mask) >> ppaf->lun_offset;
> + l.g.blk = (r.ppa & ppaf->blk_mask) >> ppaf->blk_offset;
> + l.g.pg = (r.ppa & ppaf->pg_mask) >> ppaf->pg_offset;
> + l.g.pl = (r.ppa & ppaf->pln_mask) >> ppaf->pln_offset;
> + l.g.sec = (r.ppa & ppaf->sec_mask) >> ppaf->sect_offset;
>
> return l;
> }
>

Looks good to me,

2018-03-01 10:35:54

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 02/15] lightnvm: add controller capabilities to 2.0

On 02/28/2018 04:49 PM, Javier González wrote:
> Assign missing mccap value on 2.0 path
>
> Signed-off-by: Javier González <[email protected]>
> ---
> drivers/nvme/host/lightnvm.c | 4 +++-
> include/linux/lightnvm.h | 8 +++++---
> 2 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
> index e276ace28c64..5b2024ebac76 100644
> --- a/drivers/nvme/host/lightnvm.c
> +++ b/drivers/nvme/host/lightnvm.c
> @@ -318,7 +318,7 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
> geo->ws_opt = sec_per_pg;
> geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */
>
> - geo->mccap = le32_to_cpu(src->mccap);
> + geo->cap = le32_to_cpu(src->mccap);
>
> geo->trdt = le32_to_cpu(src->trdt);
> geo->trdm = le32_to_cpu(src->trdm);
> @@ -396,6 +396,8 @@ static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
> geo->ws_opt = le32_to_cpu(id->ws_opt);
> geo->mw_cunits = le32_to_cpu(id->mw_cunits);
>
> + geo->cap = le32_to_cpu(id->mccap);
> +
> geo->trdt = le32_to_cpu(id->trdt);
> geo->trdm = le32_to_cpu(id->trdm);
> geo->tprt = le32_to_cpu(id->twrt);
> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
> index 16255fcd5250..b9f0d2070de9 100644
> --- a/include/linux/lightnvm.h
> +++ b/include/linux/lightnvm.h
> @@ -288,8 +288,10 @@ struct nvm_geo {
> u32 ws_opt; /* optimal write size */
> u32 mw_cunits; /* distance required for successful read */
>
> - /* device capabilities */
> - u32 mccap;
> + /* device capabilities. Note that this represents capabilities in 1.2
> + * and media and controller capabilities in 2.0
> + */
> + u32 cap;

Here is a list of capabilities:

1.2
Bad block mgmt
Hybrid command support

2.0

Vector copy
Double reset

The way I was thinking it would be implemented is to split the upper cap
bits to 2.0, and let the lower bits be reserved for 1.2.

Such that one would define the following:

enum {
NVM_CAP_BBM 1 << 0;
NVM_CAP_HCS 1 << 1;

NVM_CAP_VCPY 1 << 16;
NVM_CAP_DRST 1 << 17;
};

That way, the assignment from 2.0 can easily be done with cap =
le32_to_cpu(id->mccap) << 16;

and targets and other don't need to understand the difference between
1.2 and 2.0 format.
>
> /* device timings */
> u32 trdt; /* Avg. Tread (ns) */
> @@ -304,7 +306,7 @@ struct nvm_geo {
>
> /* 1.2 compatibility */
> u8 vmnt;
> - u32 cap;
> + u32 mccap;
> u32 dom;
>
> u8 mtype;
>


2018-03-01 10:43:34

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 12/15] lightnvn: pblk: use generic address format

On 02/28/2018 04:49 PM, Javier González wrote:
> Use the generic address format on common address manipulations.
>
> Signed-off-by: Javier González <[email protected]>
> ---
> drivers/lightnvm/pblk-core.c | 10 +++++-----
> drivers/lightnvm/pblk-map.c | 4 ++--
> drivers/lightnvm/pblk-sysfs.c | 4 ++--
> drivers/lightnvm/pblk.h | 4 ++--
> 4 files changed, 11 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
> index 7d0bd33f11d9..2e10b18b61e3 100644
> --- a/drivers/lightnvm/pblk-core.c
> +++ b/drivers/lightnvm/pblk-core.c
> @@ -885,7 +885,7 @@ int pblk_line_erase(struct pblk *pblk, struct pblk_line *line)
> }
>
> ppa = pblk->luns[bit].bppa; /* set ch and lun */
> - ppa.g.blk = line->id;
> + ppa.a.blk = line->id;
>
> atomic_dec(&line->left_eblks);
> WARN_ON(test_and_set_bit(bit, line->erase_bitmap));
> @@ -1686,8 +1686,8 @@ static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list,
> int i;
>
> for (i = 1; i < nr_ppas; i++)
> - WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun ||
> - ppa_list[0].g.ch != ppa_list[i].g.ch);
> + WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
> + ppa_list[0].a.ch != ppa_list[i].a.ch);
> #endif
>
> ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(30000));
> @@ -1731,8 +1731,8 @@ void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas)
> int i;
>
> for (i = 1; i < nr_ppas; i++)
> - WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun ||
> - ppa_list[0].g.ch != ppa_list[i].g.ch);
> + WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
> + ppa_list[0].a.ch != ppa_list[i].a.ch);
> #endif
>
> rlun = &pblk->luns[pos];
> diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c
> index 04e08d76ea5f..20dbaa89c9df 100644
> --- a/drivers/lightnvm/pblk-map.c
> +++ b/drivers/lightnvm/pblk-map.c
> @@ -127,7 +127,7 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
> atomic_dec(&e_line->left_eblks);
>
> *erase_ppa = rqd->ppa_list[i];
> - erase_ppa->g.blk = e_line->id;
> + erase_ppa->a.blk = e_line->id;
>
> spin_unlock(&e_line->lock);
>
> @@ -168,6 +168,6 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
> set_bit(bit, e_line->erase_bitmap);
> atomic_dec(&e_line->left_eblks);
> *erase_ppa = pblk->luns[bit].bppa; /* set ch and lun */
> - erase_ppa->g.blk = e_line->id;
> + erase_ppa->a.blk = e_line->id;
> }
> }
> diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
> index cbb5b6edb7bf..a643dc623731 100644
> --- a/drivers/lightnvm/pblk-sysfs.c
> +++ b/drivers/lightnvm/pblk-sysfs.c
> @@ -39,8 +39,8 @@ static ssize_t pblk_sysfs_luns_show(struct pblk *pblk, char *page)
> sz += snprintf(page + sz, PAGE_SIZE - sz,
> "pblk: pos:%d, ch:%d, lun:%d - %d\n",
> i,
> - rlun->bppa.g.ch,
> - rlun->bppa.g.lun,
> + rlun->bppa.a.ch,
> + rlun->bppa.a.lun,
> active);
> }
>
> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
> index dd0089fe62b9..6ac64d9eb57e 100644
> --- a/drivers/lightnvm/pblk.h
> +++ b/drivers/lightnvm/pblk.h
> @@ -936,12 +936,12 @@ static inline int pblk_pad_distance(struct pblk *pblk)
>
> static inline int pblk_ppa_to_line(struct ppa_addr p)
> {
> - return p.g.blk;
> + return p.a.blk;
> }
>
> static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
> {
> - return p.g.lun * geo->num_ch + p.g.ch;
> + return p.a.lun * geo->num_ch + p.a.ch;
> }
>
> static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
>

Would it make sense to merge this with 7/15?

2018-03-01 10:46:45

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 13/15] lightnvm: pblk: implement get log report chunk

On 02/28/2018 04:49 PM, Javier González wrote:
> 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 <[email protected]>
> ---
> drivers/lightnvm/pblk-core.c | 139 +++++++++++++++++++++++----
> drivers/lightnvm/pblk-init.c | 223 +++++++++++++++++++++++++++++++------------
> drivers/lightnvm/pblk.h | 7 ++
> include/linux/lightnvm.h | 13 +++
> 4 files changed, 301 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
> index 2e10b18b61e3..cd663855ee88 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 = &dev->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(&pblk->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 = &dev->geo;
> + struct nvm_chk_meta *chunk;
> struct pblk_line *line;
> + int pos;
>
> line = &pblk->lines[pblk_ppa_to_line(rqd->ppa_addr)];
> + pos = pblk_ppa_to_pos(geo, rqd->ppa_addr);
> + chunk = &line->chks[pos];
> +
> atomic_dec(&line->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(&pblk->inflight_io);
> @@ -92,6 +105,50 @@ 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 = &dev->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) {
> + pr_err("pblk: could not get chunk metadata (%d)\n", ret);

The error message can be omitted here. If there is an error,
nvme_nvm_get_chk_meta will already had barfed.

> + 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 = &dev->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 +1151,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 = &pblk->lm;
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> + int blk_to_erase = atomic_read(&line->blk_in_line);
> + int i;
> +
> + for (i = 0; i < lm->blk_per_line; i++) {
> + struct pblk_lun *rlun = &pblk->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),
> + line->erase_bitmap);
> + blk_to_erase--;
> + }
> + }
> +
> + return blk_to_erase;
> +}
> +
> static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
> {
> struct pblk_line_meta *lm = &pblk->lm;
> - int blk_in_line = atomic_read(&line->blk_in_line);
> + int blk_to_erase;
>
> line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_ATOMIC);
> if (!line->map_bitmap)
> @@ -1110,7 +1191,21 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
> return -ENOMEM;
> }
>
> + /* Bad blocks do not need to be erased */
> + bitmap_copy(line->erase_bitmap, line->blk_bitmap, lm->blk_per_line);
> +
> spin_lock(&line->lock);
> +
> + /* If we have not written to this line, we need to mark up free chunks
> + * as already erased
> + */
> + if (line->state == PBLK_LINESTATE_NEW) {
> + blk_to_erase = pblk_prepare_new_line(pblk, line);
> + line->state = PBLK_LINESTATE_FREE;
> + } else {
> + blk_to_erase = atomic_read(&line->blk_in_line);
> + }
> +
> if (line->state != PBLK_LINESTATE_FREE) {
> kfree(line->map_bitmap);
> kfree(line->invalid_bitmap);
> @@ -1122,15 +1217,12 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
>
> line->state = PBLK_LINESTATE_OPEN;
>
> - atomic_set(&line->left_eblks, blk_in_line);
> - atomic_set(&line->left_seblks, blk_in_line);
> + atomic_set(&line->left_eblks, blk_to_erase);
> + atomic_set(&line->left_seblks, blk_to_erase);
>
> line->meta_distance = lm->meta_distance;
> spin_unlock(&line->lock);
>
> - /* Bad blocks do not need to be erased */
> - bitmap_copy(line->erase_bitmap, line->blk_bitmap, lm->blk_per_line);
> -
> kref_init(&line->ref);
>
> return 0;
> @@ -1586,12 +1678,14 @@ static void pblk_line_should_sync_meta(struct pblk *pblk)
>
> void pblk_line_close(struct pblk *pblk, struct pblk_line *line)
> {
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> + struct pblk_line_meta *lm = &pblk->lm;
> struct pblk_line_mgmt *l_mg = &pblk->l_mg;
> struct list_head *move_list;
> + int i;
>
> #ifdef CONFIG_NVM_DEBUG
> - struct pblk_line_meta *lm = &pblk->lm;
> -
> WARN(!bitmap_full(line->map_bitmap, lm->sec_per_line),
> "pblk: corrupt closed line %d\n", line->id);
> #endif
> @@ -1613,6 +1707,15 @@ void pblk_line_close(struct pblk *pblk, struct pblk_line *line)
> line->smeta = NULL;
> line->emeta = NULL;
>
> + for (i = 0; i < lm->blk_per_line; i++) {
> + struct pblk_lun *rlun = &pblk->luns[i];
> + int pos = pblk_ppa_to_pos(geo, rlun->bppa);
> + int state = line->chks[pos].state;
> +
> + if (!(state & NVM_CHK_ST_OFFLINE))
> + state = NVM_CHK_ST_CLOSED;
> + }
> +
> spin_unlock(&line->lock);
> spin_unlock(&l_mg->gc_lock);
> }
> diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
> index 73b221c69cfd..bd2592fc3378 100644
> --- a/drivers/lightnvm/pblk-init.c
> +++ b/drivers/lightnvm/pblk-init.c
> @@ -401,6 +401,7 @@ static void pblk_line_meta_free(struct pblk_line *line)
> {
> kfree(line->blk_bitmap);
> kfree(line->erase_bitmap);
> + kfree(line->chks);
> }
>
> static void pblk_lines_free(struct pblk *pblk)
> @@ -440,55 +441,44 @@ static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
> return 0;
> }
>
> -static void *pblk_bb_get_log(struct pblk *pblk)
> +static void *pblk_bb_get_meta(struct pblk *pblk)
> {
> struct nvm_tgt_dev *dev = pblk->dev;
> struct nvm_geo *geo = &dev->geo;
> - u8 *log;
> + u8 *meta;
> int i, nr_blks, blk_per_lun;
> int ret;
>
> blk_per_lun = geo->num_chk * geo->pln_mode;
> nr_blks = blk_per_lun * geo->all_luns;
>
> - log = kmalloc(nr_blks, GFP_KERNEL);
> - if (!log)
> + meta = kmalloc(nr_blks, GFP_KERNEL);
> + if (!meta)
> return ERR_PTR(-ENOMEM);
>
> for (i = 0; i < geo->all_luns; i++) {
> struct pblk_lun *rlun = &pblk->luns[i];
> - u8 *log_pos = log + i * blk_per_lun;
> + u8 *meta_pos = meta + i * blk_per_lun;
>
> - ret = pblk_bb_get_tbl(dev, rlun, log_pos, blk_per_lun);
> + ret = pblk_bb_get_tbl(dev, rlun, meta_pos, blk_per_lun);
> if (ret) {
> - kfree(log);
> + kfree(meta);
> return ERR_PTR(-EIO);
> }
> }
>
> - return log;
> + return meta;
> }
>
> -static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line,
> - u8 *bb_log, int blk_per_line)
> +static void *pblk_chunk_get_meta(struct pblk *pblk)
> {
> struct nvm_tgt_dev *dev = pblk->dev;
> struct nvm_geo *geo = &dev->geo;
> - int i, bb_cnt = 0;
> - int blk_per_lun = geo->num_chk * geo->pln_mode;
>
> - for (i = 0; i < blk_per_line; i++) {
> - struct pblk_lun *rlun = &pblk->luns[i];
> - u8 *lun_bb_log = bb_log + i * blk_per_lun;
> -
> - if (lun_bb_log[line->id] == NVM_BLK_T_FREE)
> - continue;
> -
> - set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap);
> - bb_cnt++;
> - }
> -
> - return bb_cnt;
> + if (geo->version == NVM_OCSSD_SPEC_12)
> + return pblk_bb_get_meta(pblk);
> + else
> + return pblk_chunk_get_info(pblk);
> }
>
> static int pblk_luns_init(struct pblk *pblk, struct ppa_addr *luns)
> @@ -696,8 +686,131 @@ static int pblk_lines_alloc_metadata(struct pblk *pblk)
> return -ENOMEM;
> }
>
> -static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
> - void *chunk_log, long *nr_bad_blks)
> +static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line,
> + void *chunk_meta)
> +{
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> + struct pblk_line_meta *lm = &pblk->lm;
> + int i, chk_per_lun, nr_bad_chks = 0;
> +
> + chk_per_lun = geo->num_chk * geo->pln_mode;
> +
> + for (i = 0; i < lm->blk_per_line; i++) {
> + struct pblk_lun *rlun = &pblk->luns[i];
> + struct nvm_chk_meta *chunk;
> + int pos = pblk_ppa_to_pos(geo, rlun->bppa);
> + u8 *lun_bb_meta = chunk_meta + pos * chk_per_lun;
> +
> + chunk = &line->chks[pos];
> +
> + /*
> + * In 1.2 spec. chunk state is not persisted by the device. Thus
> + * some of the values are reset each time pblk is instantiated.
> + */
> + if (lun_bb_meta[line->id] == NVM_BLK_T_FREE)
> + chunk->state = NVM_CHK_ST_FREE;
> + else
> + chunk->state = NVM_CHK_ST_OFFLINE;
> +
> + chunk->type = NVM_CHK_TP_W_SEQ;
> + chunk->wi = 0;
> + chunk->slba = -1;
> + chunk->cnlb = geo->clba;
> + chunk->wp = 0;
> +
> + if (!(chunk->state & NVM_CHK_ST_OFFLINE))
> + continue;
> +
> + set_bit(pos, line->blk_bitmap);
> + nr_bad_chks++;
> + }
> +
> + return nr_bad_chks;
> +}
> +
> +static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
> + struct nvm_chk_meta *meta)
> +{
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> + struct pblk_line_meta *lm = &pblk->lm;
> + int i, nr_bad_chks = 0;
> +
> + for (i = 0; i < lm->blk_per_line; i++) {
> + struct pblk_lun *rlun = &pblk->luns[i];
> + struct nvm_chk_meta *chunk;
> + struct nvm_chk_meta *chunk_meta;
> + struct ppa_addr ppa;
> + int pos;
> +
> + ppa = rlun->bppa;
> + pos = pblk_ppa_to_pos(geo, ppa);
> + chunk = &line->chks[pos];
> +
> + ppa.m.chk = line->id;
> + chunk_meta = pblk_chunk_get_off(pblk, meta, ppa);
> +
> + chunk->state = chunk_meta->state;
> + chunk->type = chunk_meta->type;
> + chunk->wi = chunk_meta->wi;
> + chunk->slba = chunk_meta->slba;
> + chunk->cnlb = chunk_meta->cnlb;
> + chunk->wp = chunk_meta->wp;
> +
> + if (!(chunk->state & NVM_CHK_ST_OFFLINE))
> + continue;
> +
> + if (chunk->type & NVM_CHK_TP_SZ_SPEC) {
> + WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n");
> + continue;
> + }
> +
> + set_bit(pos, line->blk_bitmap);
> + nr_bad_chks++;
> + }
> +
> + return nr_bad_chks;
> +}
> +
> +static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
> + void *chunk_meta, int line_id)
> +{
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> + struct pblk_line_mgmt *l_mg = &pblk->l_mg;
> + struct pblk_line_meta *lm = &pblk->lm;
> + long nr_bad_chks, chk_in_line;
> +
> + line->pblk = pblk;
> + line->id = line_id;
> + line->type = PBLK_LINETYPE_FREE;
> + line->state = PBLK_LINESTATE_NEW;
> + line->gc_group = PBLK_LINEGC_NONE;
> + line->vsc = &l_mg->vsc_list[line_id];
> + spin_lock_init(&line->lock);
> +
> + if (geo->version == NVM_OCSSD_SPEC_12)
> + nr_bad_chks = pblk_setup_line_meta_12(pblk, line, chunk_meta);
> + else
> + nr_bad_chks = pblk_setup_line_meta_20(pblk, line, chunk_meta);
> +
> + chk_in_line = lm->blk_per_line - nr_bad_chks;
> + if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line ||
> + chk_in_line < lm->min_blk_line) {
> + line->state = PBLK_LINESTATE_BAD;
> + list_add_tail(&line->list, &l_mg->bad_list);
> + return 0;
> + }
> +
> + atomic_set(&line->blk_in_line, chk_in_line);
> + list_add_tail(&line->list, &l_mg->free_list);
> + l_mg->nr_free_lines++;
> +
> + return chk_in_line;
> +}
> +
> +static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line)
> {
> struct pblk_line_meta *lm = &pblk->lm;
>
> @@ -711,7 +824,13 @@ static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
> return -ENOMEM;
> }
>
> - *nr_bad_blks = pblk_bb_line(pblk, line, chunk_log, lm->blk_per_line);
> + line->chks = kmalloc(lm->blk_per_line * sizeof(struct nvm_chk_meta),
> + GFP_KERNEL);
> + if (!line->chks) {
> + kfree(line->erase_bitmap);
> + kfree(line->blk_bitmap);
> + return -ENOMEM;
> + }
>
> return 0;
> }
> @@ -723,9 +842,9 @@ static int pblk_lines_init(struct pblk *pblk)
> struct pblk_line_mgmt *l_mg = &pblk->l_mg;
> struct pblk_line_meta *lm = &pblk->lm;
> struct pblk_line *line;
> - void *chunk_log;
> + void *chunk_meta;
> unsigned int smeta_len, emeta_len;
> - long nr_bad_blks = 0, nr_free_blks = 0;
> + long nr_free_chks = 0;
> int bb_distance, max_write_ppas;
> int i, ret;
>
> @@ -842,53 +961,31 @@ static int pblk_lines_init(struct pblk *pblk)
> goto fail_free_bb_aux;
> }
>
> - chunk_log = pblk_bb_get_log(pblk);
> - if (IS_ERR(chunk_log)) {
> - pr_err("pblk: could not get bad block log (%lu)\n",
> - PTR_ERR(chunk_log));
> - ret = PTR_ERR(chunk_log);
> + chunk_meta = pblk_chunk_get_meta(pblk);
> + if (IS_ERR(chunk_meta)) {
> + pr_err("pblk: could not get chunk log (%lu)\n",
> + PTR_ERR(chunk_meta));
> + ret = PTR_ERR(chunk_meta);
> goto fail_free_lines;
> }
>
> for (i = 0; i < l_mg->nr_lines; i++) {
> - int chk_in_line;
> -
> line = &pblk->lines[i];
>
> - line->pblk = pblk;
> - line->id = i;
> - line->type = PBLK_LINETYPE_FREE;
> - line->state = PBLK_LINESTATE_FREE;
> - line->gc_group = PBLK_LINEGC_NONE;
> - line->vsc = &l_mg->vsc_list[i];
> - spin_lock_init(&line->lock);
> -
> - ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks);
> + ret = pblk_alloc_line_meta(pblk, line);
> if (ret)
> - goto fail_free_chunk_log;
> + goto fail_free_chunk_meta;
>
> - chk_in_line = lm->blk_per_line - nr_bad_blks;
> - if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line ||
> - chk_in_line < lm->min_blk_line) {
> - line->state = PBLK_LINESTATE_BAD;
> - list_add_tail(&line->list, &l_mg->bad_list);
> - continue;
> - }
> -
> - nr_free_blks += chk_in_line;
> - atomic_set(&line->blk_in_line, chk_in_line);
> -
> - l_mg->nr_free_lines++;
> - list_add_tail(&line->list, &l_mg->free_list);
> + nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
> }
>
> - pblk_set_provision(pblk, nr_free_blks);
> + pblk_set_provision(pblk, nr_free_chks);
>
> - kfree(chunk_log);
> + kfree(chunk_meta);
> return 0;
>
> -fail_free_chunk_log:
> - kfree(chunk_log);
> +fail_free_chunk_meta:
> + kfree(chunk_meta);
> while (--i >= 0)
> pblk_line_meta_free(&pblk->lines[i]);
> fail_free_lines:
> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
> index 6ac64d9eb57e..ee149766b7a0 100644
> --- a/drivers/lightnvm/pblk.h
> +++ b/drivers/lightnvm/pblk.h
> @@ -297,6 +297,7 @@ enum {
> PBLK_LINETYPE_DATA = 2,
>
> /* Line state */
> + PBLK_LINESTATE_NEW = 9,
> PBLK_LINESTATE_FREE = 10,
> PBLK_LINESTATE_OPEN = 11,
> PBLK_LINESTATE_CLOSED = 12,
> @@ -426,6 +427,8 @@ struct pblk_line {
>
> unsigned long *lun_bitmap; /* Bitmap for LUNs mapped in line */
>
> + struct nvm_chk_meta *chks; /* Chunks forming line */
> +
> struct pblk_smeta *smeta; /* Start metadata */
> struct pblk_emeta *emeta; /* End medatada */
>
> @@ -729,6 +732,10 @@ void pblk_set_sec_per_write(struct pblk *pblk, int sec_per_write);
> int pblk_setup_w_rec_rq(struct pblk *pblk, struct nvm_rq *rqd,
> struct pblk_c_ctx *c_ctx);
> void pblk_discard(struct pblk *pblk, struct bio *bio);
> +struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk);
> +struct nvm_chk_meta *pblk_chunk_get_off(struct pblk *pblk,
> + struct nvm_chk_meta *lp,
> + struct ppa_addr ppa);
> void pblk_log_write_err(struct pblk *pblk, struct nvm_rq *rqd);
> void pblk_log_read_err(struct pblk *pblk, struct nvm_rq *rqd);
> int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd);
> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
> index 9fe37f7e8185..c120b2243758 100644
> --- a/include/linux/lightnvm.h
> +++ b/include/linux/lightnvm.h
> @@ -232,6 +232,19 @@ struct nvm_addr_format {
> u64 rsv_mask[2];
> };
>
> +enum {
> + /* Chunk states */
> + NVM_CHK_ST_FREE = 1 << 0,
> + NVM_CHK_ST_CLOSED = 1 << 1,
> + NVM_CHK_ST_OPEN = 1 << 2,
> + NVM_CHK_ST_OFFLINE = 1 << 3,
> +
> + /* Chunk types */
> + NVM_CHK_TP_W_SEQ = 1 << 0,
> + NVM_CHK_TP_W_RAN = 1 << 1,
> + NVM_CHK_TP_SZ_SPEC = 1 << 4,
> +};
> +
> /*
> * Note: The structure size is linked to nvme_nvm_chk_meta such that the same
> * buffer can be used when converting from little endian to cpu addressing.
>


2018-03-01 10:50:52

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 15/15] lightnvm: pblk: implement 2.0 support

On 02/28/2018 04:49 PM, Javier González wrote:
> Implement 2.0 support in pblk. This includes the address formatting and
> mapping paths, as well as the sysfs entries for them.
>
> Signed-off-by: Javier González <[email protected]>
> ---
> drivers/lightnvm/pblk-init.c | 57 ++++++++++--
> drivers/lightnvm/pblk-sysfs.c | 36 ++++++--
> drivers/lightnvm/pblk.h | 198 ++++++++++++++++++++++++++++++++----------
> 3 files changed, 233 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
> index b3e15ef63df3..474f3f047087 100644
> --- a/drivers/lightnvm/pblk-init.c
> +++ b/drivers/lightnvm/pblk-init.c
> @@ -231,20 +231,63 @@ static int pblk_set_addrf_12(struct nvm_geo *geo,
> return dst->blk_offset + src->blk_len;
> }
>
> +static int pblk_set_addrf_20(struct nvm_geo *geo,
> + struct nvm_addr_format *adst,
> + struct pblk_addr_format *udst)
> +{
> + struct nvm_addr_format *src = &geo->addrf;
> +
> + adst->ch_len = get_count_order(geo->num_ch);
> + adst->lun_len = get_count_order(geo->num_lun);
> + adst->chk_len = src->chk_len;
> + adst->sec_len = src->sec_len;
> +
> + adst->sec_offset = 0;
> + adst->ch_offset = adst->sec_len;
> + adst->lun_offset = adst->ch_offset + adst->ch_len;
> + adst->chk_offset = adst->lun_offset + adst->lun_len;
> +
> + adst->sec_mask = ((1ULL << adst->sec_len) - 1) << adst->sec_offset;
> + adst->chk_mask = ((1ULL << adst->chk_len) - 1) << adst->chk_offset;
> + adst->lun_mask = ((1ULL << adst->lun_len) - 1) << adst->lun_offset;
> + adst->ch_mask = ((1ULL << adst->ch_len) - 1) << adst->ch_offset;
> +
> + udst->sec_stripe = geo->ws_opt;
> + udst->ch_stripe = geo->num_ch;
> + udst->lun_stripe = geo->num_lun;
> +
> + udst->sec_lun_stripe = udst->sec_stripe * udst->ch_stripe;
> + udst->sec_ws_stripe = udst->sec_lun_stripe * udst->lun_stripe;
> +
> + return adst->chk_offset + adst->chk_len;
> +}
> +
> static int pblk_set_addrf(struct pblk *pblk)
> {
> struct nvm_tgt_dev *dev = pblk->dev;
> struct nvm_geo *geo = &dev->geo;
> int mod;
>
> - div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
> - if (mod) {
> - pr_err("pblk: bad configuration of sectors/pages\n");
> + switch (geo->version) {
> + case NVM_OCSSD_SPEC_12:
> + div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
> + if (mod) {
> + pr_err("pblk: bad configuration of sectors/pages\n");
> + return -EINVAL;
> + }
> +
> + pblk->addrf_len = pblk_set_addrf_12(geo, (void *)&pblk->addrf);
> + break;
> + case NVM_OCSSD_SPEC_20:
> + pblk->addrf_len = pblk_set_addrf_20(geo, (void *)&pblk->addrf,
> + &pblk->uaddrf);
> + break;
> + default:
> + pr_err("pblk: OCSSD revision not supported (%d)\n",
> + geo->version);
> return -EINVAL;
> }
>
> - pblk->addrf_len = pblk_set_addrf_12(geo, (void *)&pblk->addrf);
> -
> return 0;
> }
>
> @@ -1117,7 +1160,9 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
> struct pblk *pblk;
> int ret;
>
> - if (geo->version != NVM_OCSSD_SPEC_12) {
> + /* pblk supports 1.2 and 2.0 versions */
> + if (!(geo->version == NVM_OCSSD_SPEC_12 ||
> + geo->version == NVM_OCSSD_SPEC_20)) {
> pr_err("pblk: OCSSD version not supported (%u)\n",
> geo->version);
> return ERR_PTR(-EINVAL);
> diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
> index a643dc623731..391f865b02d9 100644
> --- a/drivers/lightnvm/pblk-sysfs.c
> +++ b/drivers/lightnvm/pblk-sysfs.c
> @@ -113,15 +113,16 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
> {
> struct nvm_tgt_dev *dev = pblk->dev;
> struct nvm_geo *geo = &dev->geo;
> - struct nvm_addr_format_12 *ppaf;
> - struct nvm_addr_format_12 *geo_ppaf;
> ssize_t sz = 0;
>
> - ppaf = (struct nvm_addr_format_12 *)&pblk->addrf;
> - geo_ppaf = (struct nvm_addr_format_12 *)&geo->addrf;
> + if (geo->version == NVM_OCSSD_SPEC_12) {
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&pblk->addrf;
> + struct nvm_addr_format_12 *geo_ppaf =
> + (struct nvm_addr_format_12 *)&geo->addrf;
>
> - sz = snprintf(page, PAGE_SIZE,
> - "pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
> + sz = snprintf(page, PAGE_SIZE,
> + "pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
> pblk->addrf_len,
> ppaf->ch_offset, ppaf->ch_len,
> ppaf->lun_offset, ppaf->lun_len,
> @@ -130,14 +131,33 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
> ppaf->pln_offset, ppaf->pln_len,
> ppaf->sec_offset, ppaf->sec_len);
>
> - sz += snprintf(page + sz, PAGE_SIZE - sz,
> - "device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
> + sz += snprintf(page + sz, PAGE_SIZE - sz,
> + "device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
> geo_ppaf->ch_offset, geo_ppaf->ch_len,
> geo_ppaf->lun_offset, geo_ppaf->lun_len,
> geo_ppaf->blk_offset, geo_ppaf->blk_len,
> geo_ppaf->pg_offset, geo_ppaf->pg_len,
> geo_ppaf->pln_offset, geo_ppaf->pln_len,
> geo_ppaf->sec_offset, geo_ppaf->sec_len);
> + } else {
> + struct nvm_addr_format *ppaf = &pblk->addrf;
> + struct nvm_addr_format *geo_ppaf = &geo->addrf;
> +
> + sz = snprintf(page, PAGE_SIZE,
> + "pblk:(s:%d)ch:%d/%d,lun:%d/%d,chk:%d/%d/sec:%d/%d\n",
> + pblk->addrf_len,
> + ppaf->ch_offset, ppaf->ch_len,
> + ppaf->lun_offset, ppaf->lun_len,
> + ppaf->chk_offset, ppaf->chk_len,
> + ppaf->sec_offset, ppaf->sec_len);
> +
> + sz += snprintf(page + sz, PAGE_SIZE - sz,
> + "device:ch:%d/%d,lun:%d/%d,chk:%d/%d,sec:%d/%d\n",
> + geo_ppaf->ch_offset, geo_ppaf->ch_len,
> + geo_ppaf->lun_offset, geo_ppaf->lun_len,
> + geo_ppaf->chk_offset, geo_ppaf->chk_len,
> + geo_ppaf->sec_offset, geo_ppaf->sec_len);
> + }
>
> return sz;
> }
> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
> index ee149766b7a0..1deddd38c0ac 100644
> --- a/drivers/lightnvm/pblk.h
> +++ b/drivers/lightnvm/pblk.h
> @@ -561,6 +561,18 @@ enum {
> PBLK_STATE_STOPPED = 3,
> };
>
> +/* Internal format to support not power-of-2 device formats */
> +struct pblk_addr_format {
> + /* gen to dev */
> + int sec_stripe;
> + int ch_stripe;
> + int lun_stripe;
> +
> + /* dev to gen */
> + int sec_lun_stripe;
> + int sec_ws_stripe;
> +};
> +
> struct pblk {
> struct nvm_tgt_dev *dev;
> struct gendisk *disk;
> @@ -573,7 +585,8 @@ struct pblk {
> struct pblk_line_mgmt l_mg; /* Line management */
> struct pblk_line_meta lm; /* Line metadata */
>
> - struct nvm_addr_format addrf;
> + struct nvm_addr_format addrf; /* Aligned address format */
> + struct pblk_addr_format uaddrf; /* Unaligned address format */
> int addrf_len;
>
> struct pblk_rb rwb;
> @@ -954,17 +967,43 @@ static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
> static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
> u64 line_id)
> {
> - struct nvm_addr_format_12 *ppaf =
> - (struct nvm_addr_format_12 *)&pblk->addrf;
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> struct ppa_addr ppa;
>
> - ppa.ppa = 0;
> - ppa.g.blk = line_id;
> - ppa.g.pg = (paddr & ppaf->pg_mask) >> ppaf->pg_offset;
> - ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
> - ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
> - ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
> - ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sec_offset;
> + if (geo->version == NVM_OCSSD_SPEC_12) {
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&pblk->addrf;
> +
> + ppa.ppa = 0;
> + ppa.g.blk = line_id;
> + ppa.g.pg = (paddr & ppaf->pg_mask) >> ppaf->pg_offset;
> + ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
> + ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
> + ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
> + ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sec_offset;
> + } else {
> + struct pblk_addr_format *uaddrf = &pblk->uaddrf;
> + int secs, chnls, luns;
> +
> + ppa.ppa = 0;
> +
> + ppa.m.chk = line_id;
> +
> + div_u64_rem(paddr, uaddrf->sec_stripe, &secs);
> + ppa.m.sec = secs;
> +
> + sector_div(paddr, uaddrf->sec_stripe);
> + div_u64_rem(paddr, uaddrf->ch_stripe, &chnls);
> + ppa.m.grp = chnls;
> +
> + sector_div(paddr, uaddrf->ch_stripe);
> + div_u64_rem(paddr, uaddrf->lun_stripe, &luns);
> + ppa.m.pu = luns;
> +
> + sector_div(paddr, uaddrf->lun_stripe);
> + ppa.m.sec += uaddrf->sec_stripe * paddr;
> + }
>
> return ppa;
> }
> @@ -972,15 +1011,32 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
> static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
> struct ppa_addr p)
> {
> - struct nvm_addr_format_12 *ppaf =
> - (struct nvm_addr_format_12 *)&pblk->addrf;
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> u64 paddr;
>
> - paddr = (u64)p.g.ch << ppaf->ch_offset;
> - paddr |= (u64)p.g.lun << ppaf->lun_offset;
> - paddr |= (u64)p.g.pg << ppaf->pg_offset;
> - paddr |= (u64)p.g.pl << ppaf->pln_offset;
> - paddr |= (u64)p.g.sec << ppaf->sec_offset;
> + if (geo->version == NVM_OCSSD_SPEC_12) {
> + struct nvm_addr_format_12 *ppaf =
> + (struct nvm_addr_format_12 *)&pblk->addrf;
> +
> + paddr = (u64)p.g.ch << ppaf->ch_offset;
> + paddr |= (u64)p.g.lun << ppaf->lun_offset;
> + paddr |= (u64)p.g.pg << ppaf->pg_offset;
> + paddr |= (u64)p.g.pl << ppaf->pln_offset;
> + paddr |= (u64)p.g.sec << ppaf->sec_offset;
> + } else {
> + struct pblk_addr_format *uaddrf = &pblk->uaddrf;
> + u64 secs = (u64)p.m.sec;
> + int sec_stripe;
> +
> + paddr = (u64)p.m.grp * uaddrf->sec_stripe;
> + paddr += (u64)p.m.pu * uaddrf->sec_lun_stripe;
> +
> + div_u64_rem(secs, uaddrf->sec_stripe, &sec_stripe);
> + sector_div(secs, uaddrf->sec_stripe);
> + paddr += secs * uaddrf->sec_ws_stripe;
> + paddr += sec_stripe;
> + }
>
> return paddr;
> }
> @@ -997,15 +1053,37 @@ static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
> ppa64.c.line = ppa32 & ((~0U) >> 1);
> ppa64.c.is_cached = 1;
> } else {
> - struct nvm_addr_format_12 *ppaf =
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> +
> + if (geo->version == NVM_OCSSD_SPEC_12) {
> + struct nvm_addr_format_12 *ppaf =
> (struct nvm_addr_format_12 *)&pblk->addrf;
>
> - ppa64.g.ch = (ppa32 & ppaf->ch_mask) >> ppaf->ch_offset;
> - ppa64.g.lun = (ppa32 & ppaf->lun_mask) >> ppaf->lun_offset;
> - ppa64.g.blk = (ppa32 & ppaf->blk_mask) >> ppaf->blk_offset;
> - ppa64.g.pg = (ppa32 & ppaf->pg_mask) >> ppaf->pg_offset;
> - ppa64.g.pl = (ppa32 & ppaf->pln_mask) >> ppaf->pln_offset;
> - ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> ppaf->sec_offset;
> + ppa64.g.ch = (ppa32 & ppaf->ch_mask) >>
> + ppaf->ch_offset;
> + ppa64.g.lun = (ppa32 & ppaf->lun_mask) >>
> + ppaf->lun_offset;
> + ppa64.g.blk = (ppa32 & ppaf->blk_mask) >>
> + ppaf->blk_offset;
> + ppa64.g.pg = (ppa32 & ppaf->pg_mask) >>
> + ppaf->pg_offset;
> + ppa64.g.pl = (ppa32 & ppaf->pln_mask) >>
> + ppaf->pln_offset;
> + ppa64.g.sec = (ppa32 & ppaf->sec_mask) >>
> + ppaf->sec_offset;
> + } else {
> + struct nvm_addr_format *lbaf = &pblk->addrf;
> +
> + ppa64.m.grp = (ppa32 & lbaf->ch_mask) >>
> + lbaf->ch_offset;
> + ppa64.m.pu = (ppa32 & lbaf->lun_mask) >>
> + lbaf->lun_offset;
> + ppa64.m.chk = (ppa32 & lbaf->chk_mask) >>
> + lbaf->chk_offset;
> + ppa64.m.sec = (ppa32 & lbaf->sec_mask) >>
> + lbaf->sec_offset;
> + }
> }
>
> return ppa64;
> @@ -1021,15 +1099,27 @@ static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
> ppa32 |= ppa64.c.line;
> ppa32 |= 1U << 31;
> } else {
> - struct nvm_addr_format_12 *ppaf =
> + struct nvm_tgt_dev *dev = pblk->dev;
> + struct nvm_geo *geo = &dev->geo;
> +
> + if (geo->version == NVM_OCSSD_SPEC_12) {
> + struct nvm_addr_format_12 *ppaf =
> (struct nvm_addr_format_12 *)&pblk->addrf;
>
> - ppa32 |= ppa64.g.ch << ppaf->ch_offset;
> - ppa32 |= ppa64.g.lun << ppaf->lun_offset;
> - ppa32 |= ppa64.g.blk << ppaf->blk_offset;
> - ppa32 |= ppa64.g.pg << ppaf->pg_offset;
> - ppa32 |= ppa64.g.pl << ppaf->pln_offset;
> - ppa32 |= ppa64.g.sec << ppaf->sec_offset;
> + ppa32 |= ppa64.g.ch << ppaf->ch_offset;
> + ppa32 |= ppa64.g.lun << ppaf->lun_offset;
> + ppa32 |= ppa64.g.blk << ppaf->blk_offset;
> + ppa32 |= ppa64.g.pg << ppaf->pg_offset;
> + ppa32 |= ppa64.g.pl << ppaf->pln_offset;
> + ppa32 |= ppa64.g.sec << ppaf->sec_offset;
> + } else {
> + struct nvm_addr_format *lbaf = &pblk->addrf;
> +
> + ppa32 |= ppa64.m.grp << lbaf->ch_offset;
> + ppa32 |= ppa64.m.pu << lbaf->lun_offset;
> + ppa32 |= ppa64.m.chk << lbaf->chk_offset;
> + ppa32 |= ppa64.m.sec << lbaf->sec_offset;
> + }
> }
>
> return ppa32;
> @@ -1147,6 +1237,9 @@ static inline int pblk_set_progr_mode(struct pblk *pblk, int type)
> struct nvm_geo *geo = &dev->geo;
> int flags;
>
> + if (geo->version == NVM_OCSSD_SPEC_20)
> + return 0;
> +
> flags = geo->pln_mode >> 1;
>
> if (type == PBLK_WRITE)
> @@ -1166,6 +1259,9 @@ static inline int pblk_set_read_mode(struct pblk *pblk, int type)
> struct nvm_geo *geo = &dev->geo;
> int flags;
>
> + if (geo->version == NVM_OCSSD_SPEC_20)
> + return 0;
> +
> flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
> if (type == PBLK_READ_SEQUENTIAL)
> flags |= geo->pln_mode >> 1;
> @@ -1179,16 +1275,21 @@ static inline int pblk_io_aligned(struct pblk *pblk, int nr_secs)
> }
>
> #ifdef CONFIG_NVM_DEBUG
> -static inline void print_ppa(struct ppa_addr *p, char *msg, int error)
> +static inline void print_ppa(struct nvm_geo *geo, struct ppa_addr *p,
> + char *msg, int error)
> {
> if (p->c.is_cached) {
> pr_err("ppa: (%s: %x) cache line: %llu\n",
> msg, error, (u64)p->c.line);
> - } else {
> + } else if (geo->version == NVM_OCSSD_SPEC_12) {
> pr_err("ppa: (%s: %x):ch:%d,lun:%d,blk:%d,pg:%d,pl:%d,sec:%d\n",
> msg, error,
> p->g.ch, p->g.lun, p->g.blk,
> p->g.pg, p->g.pl, p->g.sec);
> + } else {
> + pr_err("ppa: (%s: %x):ch:%d,lun:%d,chk:%d,sec:%d\n",
> + msg, error,
> + p->m.grp, p->m.pu, p->m.chk, p->m.sec);
> }
> }
>
> @@ -1198,13 +1299,13 @@ static inline void pblk_print_failed_rqd(struct pblk *pblk, struct nvm_rq *rqd,
> int bit = -1;
>
> if (rqd->nr_ppas == 1) {
> - print_ppa(&rqd->ppa_addr, "rqd", error);
> + print_ppa(&pblk->dev->geo, &rqd->ppa_addr, "rqd", error);
> return;
> }
>
> while ((bit = find_next_bit((void *)&rqd->ppa_status, rqd->nr_ppas,
> bit + 1)) < rqd->nr_ppas) {
> - print_ppa(&rqd->ppa_list[bit], "rqd", error);
> + print_ppa(&pblk->dev->geo, &rqd->ppa_list[bit], "rqd", error);
> }
>
> pr_err("error:%d, ppa_status:%llx\n", error, rqd->ppa_status);
> @@ -1220,16 +1321,25 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev,
> for (i = 0; i < nr_ppas; i++) {
> ppa = &ppas[i];
>
> - if (!ppa->c.is_cached &&
> - ppa->g.ch < geo->num_ch &&
> - ppa->g.lun < geo->num_lun &&
> - ppa->g.pl < geo->num_pln &&
> - ppa->g.blk < geo->num_chk &&
> - ppa->g.pg < geo->num_pg &&
> - ppa->g.sec < geo->ws_min)
> - continue;
> + if (geo->version == NVM_OCSSD_SPEC_12) {
> + if (!ppa->c.is_cached &&
> + ppa->g.ch < geo->num_ch &&
> + ppa->g.lun < geo->num_lun &&
> + ppa->g.pl < geo->num_pln &&
> + ppa->g.blk < geo->num_chk &&
> + ppa->g.pg < geo->num_pg &&
> + ppa->g.sec < geo->ws_min)
> + continue;
> + } else {
> + if (!ppa->c.is_cached &&
> + ppa->m.grp < geo->num_ch &&
> + ppa->m.pu < geo->num_lun &&
> + ppa->m.chk < geo->num_chk &&
> + ppa->m.sec < geo->clba)
> + continue;
> + }
>
> - print_ppa(ppa, "boundary", i);
> + print_ppa(geo, ppa, "boundary", i);
>
> return 1;
> }
>

Ok, I think this is close to be good such that the patches can be picked
up in v5.

2018-03-01 11:03:43

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 09/15] lightnvm: implement get log report chunk helpers

On 02/28/2018 04:49 PM, Javier González wrote:
> The 2.0 spec provides a report chunk log page that can be retrieved
> using the stangard nvme get log page. This replaces the dedicated
> get/put bad block table in 1.2.
>
> This patch implements the helper functions to allow targets retrieve the
> chunk metadata using get log page. It makes nvme_get_log_ext available
> outside of nvme core so that we can use it form lightnvm.
>
> Signed-off-by: Javier González <[email protected]>
> ---
> drivers/lightnvm/core.c | 11 +++++++
> drivers/nvme/host/core.c | 6 ++--
> drivers/nvme/host/lightnvm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++
> drivers/nvme/host/nvme.h | 3 ++
> include/linux/lightnvm.h | 24 ++++++++++++++
> 5 files changed, 115 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
> index ed33e0b11788..4141871f460d 100644
> --- a/drivers/lightnvm/core.c
> +++ b/drivers/lightnvm/core.c
> @@ -712,6 +712,17 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev,
> nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list);
> }
>
> +int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta,
> + struct ppa_addr ppa, int nchks)
> +{
> + struct nvm_dev *dev = tgt_dev->parent;
> +
> + nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
> +
> + return dev->ops->get_chk_meta(tgt_dev->parent, meta,
> + (sector_t)ppa.ppa, nchks);
> +}
> +EXPORT_SYMBOL(nvm_get_chunk_meta);
>
> int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
> int nr_ppas, int type)
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 2e9e9f973a75..af642ce6ba69 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2127,9 +2127,9 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
> return ret;
> }
>
> -static int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
> - u8 log_page, void *log,
> - size_t size, size_t offset)
> +int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
> + u8 log_page, void *log,
> + size_t size, size_t offset)
> {
> struct nvme_command c = { };
> unsigned long dwlen = size / 4 - 1;
> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
> index f7135659f918..a1796241040f 100644
> --- a/drivers/nvme/host/lightnvm.c
> +++ b/drivers/nvme/host/lightnvm.c
> @@ -35,6 +35,10 @@ enum nvme_nvm_admin_opcode {
> nvme_nvm_admin_set_bb_tbl = 0xf1,
> };
>
> +enum nvme_nvm_log_page {
> + NVME_NVM_LOG_REPORT_CHUNK = 0xca,
> +};
> +
> struct nvme_nvm_ph_rw {
> __u8 opcode;
> __u8 flags;
> @@ -236,6 +240,16 @@ struct nvme_nvm_id20 {
> __u8 vs[1024];
> };
>
> +struct nvme_nvm_chk_meta {
> + __u8 state;
> + __u8 type;
> + __u8 wi;
> + __u8 rsvd[5];
> + __le64 slba;
> + __le64 cnlb;
> + __le64 wp;
> +};
> +
> /*
> * Check we didn't inadvertently grow the command struct
> */
> @@ -252,6 +266,9 @@ static inline void _nvme_nvm_check_size(void)
> BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64);
> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8);
> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != 32);
> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) !=
> + sizeof(struct nvm_chk_meta));
> }
>
> static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
> @@ -555,6 +572,61 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas,
> return ret;
> }
>
> +/*
> + * Expect the lba in device format
> + */
> +static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
> + struct nvm_chk_meta *meta,
> + sector_t slba, int nchks)
> +{
> + struct nvm_geo *geo = &ndev->geo;
> + struct nvme_ns *ns = ndev->q->queuedata;
> + struct nvme_ctrl *ctrl = ns->ctrl;
> + struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta;
> + struct ppa_addr ppa;
> + size_t left = nchks * sizeof(struct nvme_nvm_chk_meta);
> + size_t log_pos, offset, len;
> + int ret, i;
> +
> + /* Normalize lba address space to obtain log offset */
> + ppa.ppa = slba;
> + ppa = dev_to_generic_addr(ndev, ppa);
> +
> + log_pos = ppa.m.chk;
> + log_pos += ppa.m.pu * geo->num_chk;
> + log_pos += ppa.m.grp * geo->num_lun * geo->num_chk;

Why is this done?

2018-03-01 11:05:25

by Javier Gonzalez

[permalink] [raw]
Subject: Re: [PATCH 09/15] lightnvm: implement get log report chunk helpers

> On 1 Mar 2018, at 11.40, Matias Bjørling <[email protected]> wrote:
>
> On 02/28/2018 04:49 PM, Javier González wrote:
>> The 2.0 spec provides a report chunk log page that can be retrieved
>> using the stangard nvme get log page. This replaces the dedicated
>> get/put bad block table in 1.2.
>> This patch implements the helper functions to allow targets retrieve the
>> chunk metadata using get log page. It makes nvme_get_log_ext available
>> outside of nvme core so that we can use it form lightnvm.
>> Signed-off-by: Javier González <[email protected]>
>> ---
>> drivers/lightnvm/core.c | 11 +++++++
>> drivers/nvme/host/core.c | 6 ++--
>> drivers/nvme/host/lightnvm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++
>> drivers/nvme/host/nvme.h | 3 ++
>> include/linux/lightnvm.h | 24 ++++++++++++++
>> 5 files changed, 115 insertions(+), 3 deletions(-)
>> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
>> index ed33e0b11788..4141871f460d 100644
>> --- a/drivers/lightnvm/core.c
>> +++ b/drivers/lightnvm/core.c
>> @@ -712,6 +712,17 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev,
>> nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list);
>> }
>> +int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta,
>> + struct ppa_addr ppa, int nchks)
>> +{
>> + struct nvm_dev *dev = tgt_dev->parent;
>> +
>> + nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
>> +
>> + return dev->ops->get_chk_meta(tgt_dev->parent, meta,
>> + (sector_t)ppa.ppa, nchks);
>> +}
>> +EXPORT_SYMBOL(nvm_get_chunk_meta);
>> int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
>> int nr_ppas, int type)
>> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
>> index 2e9e9f973a75..af642ce6ba69 100644
>> --- a/drivers/nvme/host/core.c
>> +++ b/drivers/nvme/host/core.c
>> @@ -2127,9 +2127,9 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
>> return ret;
>> }
>> -static int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
>> - u8 log_page, void *log,
>> - size_t size, size_t offset)
>> +int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
>> + u8 log_page, void *log,
>> + size_t size, size_t offset)
>> {
>> struct nvme_command c = { };
>> unsigned long dwlen = size / 4 - 1;
>> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
>> index f7135659f918..a1796241040f 100644
>> --- a/drivers/nvme/host/lightnvm.c
>> +++ b/drivers/nvme/host/lightnvm.c
>> @@ -35,6 +35,10 @@ enum nvme_nvm_admin_opcode {
>> nvme_nvm_admin_set_bb_tbl = 0xf1,
>> };
>> +enum nvme_nvm_log_page {
>> + NVME_NVM_LOG_REPORT_CHUNK = 0xca,
>> +};
>> +
>> struct nvme_nvm_ph_rw {
>> __u8 opcode;
>> __u8 flags;
>> @@ -236,6 +240,16 @@ struct nvme_nvm_id20 {
>> __u8 vs[1024];
>> };
>> +struct nvme_nvm_chk_meta {
>> + __u8 state;
>> + __u8 type;
>> + __u8 wi;
>> + __u8 rsvd[5];
>> + __le64 slba;
>> + __le64 cnlb;
>> + __le64 wp;
>> +};
>> +
>> /*
>> * Check we didn't inadvertently grow the command struct
>> */
>> @@ -252,6 +266,9 @@ static inline void _nvme_nvm_check_size(void)
>> BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64);
>> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8);
>> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
>> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != 32);
>> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) !=
>> + sizeof(struct nvm_chk_meta));
>> }
>> static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
>> @@ -555,6 +572,61 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas,
>> return ret;
>> }
>> +/*
>> + * Expect the lba in device format
>> + */
>> +static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
>> + struct nvm_chk_meta *meta,
>> + sector_t slba, int nchks)
>> +{
>> + struct nvm_geo *geo = &ndev->geo;
>> + struct nvme_ns *ns = ndev->q->queuedata;
>> + struct nvme_ctrl *ctrl = ns->ctrl;
>> + struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta;
>> + struct ppa_addr ppa;
>> + size_t left = nchks * sizeof(struct nvme_nvm_chk_meta);
>> + size_t log_pos, offset, len;
>> + int ret, i;
>> +
>> + /* Normalize lba address space to obtain log offset */
>> + ppa.ppa = slba;
>> + ppa = dev_to_generic_addr(ndev, ppa);
>> +
>> + log_pos = ppa.m.chk;
>> + log_pos += ppa.m.pu * geo->num_chk;
>> + log_pos += ppa.m.grp * geo->num_lun * geo->num_chk;
>
> Why is this done?

The log page does not map to the lba space. You need to convert it to
get one chunk at a time in the format.

GRP:PU:CHK

I can see why taking a lba as argument is better than a ppa, since users
might use the lbas directly, but the conversion needs to be done
somewhere.

Javier


Attachments:
signature.asc (849.00 B)
Message signed with OpenPGP

2018-03-01 11:07:03

by Javier González

[permalink] [raw]
Subject: Re: [PATCH 12/15] lightnvn: pblk: use generic address format

> On 1 Mar 2018, at 11.41, Matias Bjørling <[email protected]> wrote:
>
> On 02/28/2018 04:49 PM, Javier González wrote:
>> Use the generic address format on common address manipulations.
>> Signed-off-by: Javier González <[email protected]>
>> ---
>> drivers/lightnvm/pblk-core.c | 10 +++++-----
>> drivers/lightnvm/pblk-map.c | 4 ++--
>> drivers/lightnvm/pblk-sysfs.c | 4 ++--
>> drivers/lightnvm/pblk.h | 4 ++--
>> 4 files changed, 11 insertions(+), 11 deletions(-)
>> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
>> index 7d0bd33f11d9..2e10b18b61e3 100644
>> --- a/drivers/lightnvm/pblk-core.c
>> +++ b/drivers/lightnvm/pblk-core.c
>> @@ -885,7 +885,7 @@ int pblk_line_erase(struct pblk *pblk, struct pblk_line *line)
>> }
>> ppa = pblk->luns[bit].bppa; /* set ch and lun */
>> - ppa.g.blk = line->id;
>> + ppa.a.blk = line->id;
>> atomic_dec(&line->left_eblks);
>> WARN_ON(test_and_set_bit(bit, line->erase_bitmap));
>> @@ -1686,8 +1686,8 @@ static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list,
>> int i;
>> for (i = 1; i < nr_ppas; i++)
>> - WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun ||
>> - ppa_list[0].g.ch != ppa_list[i].g.ch);
>> + WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
>> + ppa_list[0].a.ch != ppa_list[i].a.ch);
>> #endif
>> ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(30000));
>> @@ -1731,8 +1731,8 @@ void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas)
>> int i;
>> for (i = 1; i < nr_ppas; i++)
>> - WARN_ON(ppa_list[0].g.lun != ppa_list[i].g.lun ||
>> - ppa_list[0].g.ch != ppa_list[i].g.ch);
>> + WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
>> + ppa_list[0].a.ch != ppa_list[i].a.ch);
>> #endif
>> rlun = &pblk->luns[pos];
>> diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c
>> index 04e08d76ea5f..20dbaa89c9df 100644
>> --- a/drivers/lightnvm/pblk-map.c
>> +++ b/drivers/lightnvm/pblk-map.c
>> @@ -127,7 +127,7 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
>> atomic_dec(&e_line->left_eblks);
>> *erase_ppa = rqd->ppa_list[i];
>> - erase_ppa->g.blk = e_line->id;
>> + erase_ppa->a.blk = e_line->id;
>> spin_unlock(&e_line->lock);
>> @@ -168,6 +168,6 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
>> set_bit(bit, e_line->erase_bitmap);
>> atomic_dec(&e_line->left_eblks);
>> *erase_ppa = pblk->luns[bit].bppa; /* set ch and lun */
>> - erase_ppa->g.blk = e_line->id;
>> + erase_ppa->a.blk = e_line->id;
>> }
>> }
>> diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
>> index cbb5b6edb7bf..a643dc623731 100644
>> --- a/drivers/lightnvm/pblk-sysfs.c
>> +++ b/drivers/lightnvm/pblk-sysfs.c
>> @@ -39,8 +39,8 @@ static ssize_t pblk_sysfs_luns_show(struct pblk *pblk, char *page)
>> sz += snprintf(page + sz, PAGE_SIZE - sz,
>> "pblk: pos:%d, ch:%d, lun:%d - %d\n",
>> i,
>> - rlun->bppa.g.ch,
>> - rlun->bppa.g.lun,
>> + rlun->bppa.a.ch,
>> + rlun->bppa.a.lun,
>> active);
>> }
>> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
>> index dd0089fe62b9..6ac64d9eb57e 100644
>> --- a/drivers/lightnvm/pblk.h
>> +++ b/drivers/lightnvm/pblk.h
>> @@ -936,12 +936,12 @@ static inline int pblk_pad_distance(struct pblk *pblk)
>> static inline int pblk_ppa_to_line(struct ppa_addr p)
>> {
>> - return p.g.blk;
>> + return p.a.blk;
>> }
>> static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
>> {
>> - return p.g.lun * geo->num_ch + p.g.ch;
>> + return p.a.lun * geo->num_ch + p.a.ch;
>> }
>> static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
>
> Would it make sense to merge this with 7/15?

Sure. I've tried to decouple pblk and lightnvm core patches, but they
can go together. I'll merge in V5.

Javier


Attachments:
signature.asc (849.00 B)
Message signed with OpenPGP

2018-03-01 11:53:15

by Matias Bjørling

[permalink] [raw]
Subject: Re: [PATCH 09/15] lightnvm: implement get log report chunk helpers

On 03/01/2018 12:02 PM, Javier Gonzalez wrote:
>> On 1 Mar 2018, at 11.40, Matias Bjørling <[email protected]> wrote:
>>
>> On 02/28/2018 04:49 PM, Javier González wrote:
>>> The 2.0 spec provides a report chunk log page that can be retrieved
>>> using the stangard nvme get log page. This replaces the dedicated
>>> get/put bad block table in 1.2.
>>> This patch implements the helper functions to allow targets retrieve the
>>> chunk metadata using get log page. It makes nvme_get_log_ext available
>>> outside of nvme core so that we can use it form lightnvm.
>>> Signed-off-by: Javier González <[email protected]>
>>> ---
>>> drivers/lightnvm/core.c | 11 +++++++
>>> drivers/nvme/host/core.c | 6 ++--
>>> drivers/nvme/host/lightnvm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++
>>> drivers/nvme/host/nvme.h | 3 ++
>>> include/linux/lightnvm.h | 24 ++++++++++++++
>>> 5 files changed, 115 insertions(+), 3 deletions(-)
>>> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
>>> index ed33e0b11788..4141871f460d 100644
>>> --- a/drivers/lightnvm/core.c
>>> +++ b/drivers/lightnvm/core.c
>>> @@ -712,6 +712,17 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev,
>>> nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list);
>>> }
>>> +int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta,
>>> + struct ppa_addr ppa, int nchks)
>>> +{
>>> + struct nvm_dev *dev = tgt_dev->parent;
>>> +
>>> + nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
>>> +
>>> + return dev->ops->get_chk_meta(tgt_dev->parent, meta,
>>> + (sector_t)ppa.ppa, nchks);
>>> +}
>>> +EXPORT_SYMBOL(nvm_get_chunk_meta);
>>> int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
>>> int nr_ppas, int type)
>>> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
>>> index 2e9e9f973a75..af642ce6ba69 100644
>>> --- a/drivers/nvme/host/core.c
>>> +++ b/drivers/nvme/host/core.c
>>> @@ -2127,9 +2127,9 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
>>> return ret;
>>> }
>>> -static int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
>>> - u8 log_page, void *log,
>>> - size_t size, size_t offset)
>>> +int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
>>> + u8 log_page, void *log,
>>> + size_t size, size_t offset)
>>> {
>>> struct nvme_command c = { };
>>> unsigned long dwlen = size / 4 - 1;
>>> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
>>> index f7135659f918..a1796241040f 100644
>>> --- a/drivers/nvme/host/lightnvm.c
>>> +++ b/drivers/nvme/host/lightnvm.c
>>> @@ -35,6 +35,10 @@ enum nvme_nvm_admin_opcode {
>>> nvme_nvm_admin_set_bb_tbl = 0xf1,
>>> };
>>> +enum nvme_nvm_log_page {
>>> + NVME_NVM_LOG_REPORT_CHUNK = 0xca,
>>> +};
>>> +
>>> struct nvme_nvm_ph_rw {
>>> __u8 opcode;
>>> __u8 flags;
>>> @@ -236,6 +240,16 @@ struct nvme_nvm_id20 {
>>> __u8 vs[1024];
>>> };
>>> +struct nvme_nvm_chk_meta {
>>> + __u8 state;
>>> + __u8 type;
>>> + __u8 wi;
>>> + __u8 rsvd[5];
>>> + __le64 slba;
>>> + __le64 cnlb;
>>> + __le64 wp;
>>> +};
>>> +
>>> /*
>>> * Check we didn't inadvertently grow the command struct
>>> */
>>> @@ -252,6 +266,9 @@ static inline void _nvme_nvm_check_size(void)
>>> BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64);
>>> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8);
>>> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
>>> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != 32);
>>> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) !=
>>> + sizeof(struct nvm_chk_meta));
>>> }
>>> static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
>>> @@ -555,6 +572,61 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas,
>>> return ret;
>>> }
>>> +/*
>>> + * Expect the lba in device format
>>> + */
>>> +static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
>>> + struct nvm_chk_meta *meta,
>>> + sector_t slba, int nchks)
>>> +{
>>> + struct nvm_geo *geo = &ndev->geo;
>>> + struct nvme_ns *ns = ndev->q->queuedata;
>>> + struct nvme_ctrl *ctrl = ns->ctrl;
>>> + struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta;
>>> + struct ppa_addr ppa;
>>> + size_t left = nchks * sizeof(struct nvme_nvm_chk_meta);
>>> + size_t log_pos, offset, len;
>>> + int ret, i;
>>> +
>>> + /* Normalize lba address space to obtain log offset */
>>> + ppa.ppa = slba;
>>> + ppa = dev_to_generic_addr(ndev, ppa);
>>> +
>>> + log_pos = ppa.m.chk;
>>> + log_pos += ppa.m.pu * geo->num_chk;
>>> + log_pos += ppa.m.grp * geo->num_lun * geo->num_chk;
>>
>> Why is this done?
>
> The log page does not map to the lba space. You need to convert it to
> get one chunk at a time in the format.
>
> GRP:PU:CHK
>
> I can see why taking a lba as argument is better than a ppa, since users
> might use the lbas directly, but the conversion needs to be done
> somewhere.
>

Good point. I guess this is clash between the two APIs. Chunk metadata
being laid out sequentially, while the address space is sparse. I'm good
with the conversion being in the fn.


2018-03-01 11:56:01

by Javier Gonzalez

[permalink] [raw]
Subject: Re: [PATCH 09/15] lightnvm: implement get log report chunk helpers


> On 1 Mar 2018, at 12.51, Matias Bjørling <[email protected]> wrote:
>
> On 03/01/2018 12:02 PM, Javier Gonzalez wrote:
>>> On 1 Mar 2018, at 11.40, Matias Bjørling <[email protected]> wrote:
>>>
>>> On 02/28/2018 04:49 PM, Javier González wrote:
>>>> The 2.0 spec provides a report chunk log page that can be retrieved
>>>> using the stangard nvme get log page. This replaces the dedicated
>>>> get/put bad block table in 1.2.
>>>> This patch implements the helper functions to allow targets retrieve the
>>>> chunk metadata using get log page. It makes nvme_get_log_ext available
>>>> outside of nvme core so that we can use it form lightnvm.
>>>> Signed-off-by: Javier González <[email protected]>
>>>> ---
>>>> drivers/lightnvm/core.c | 11 +++++++
>>>> drivers/nvme/host/core.c | 6 ++--
>>>> drivers/nvme/host/lightnvm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++
>>>> drivers/nvme/host/nvme.h | 3 ++
>>>> include/linux/lightnvm.h | 24 ++++++++++++++
>>>> 5 files changed, 115 insertions(+), 3 deletions(-)
>>>> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
>>>> index ed33e0b11788..4141871f460d 100644
>>>> --- a/drivers/lightnvm/core.c
>>>> +++ b/drivers/lightnvm/core.c
>>>> @@ -712,6 +712,17 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev,
>>>> nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list);
>>>> }
>>>> +int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta,
>>>> + struct ppa_addr ppa, int nchks)
>>>> +{
>>>> + struct nvm_dev *dev = tgt_dev->parent;
>>>> +
>>>> + nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
>>>> +
>>>> + return dev->ops->get_chk_meta(tgt_dev->parent, meta,
>>>> + (sector_t)ppa.ppa, nchks);
>>>> +}
>>>> +EXPORT_SYMBOL(nvm_get_chunk_meta);
>>>> int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
>>>> int nr_ppas, int type)
>>>> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
>>>> index 2e9e9f973a75..af642ce6ba69 100644
>>>> --- a/drivers/nvme/host/core.c
>>>> +++ b/drivers/nvme/host/core.c
>>>> @@ -2127,9 +2127,9 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
>>>> return ret;
>>>> }
>>>> -static int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
>>>> - u8 log_page, void *log,
>>>> - size_t size, size_t offset)
>>>> +int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
>>>> + u8 log_page, void *log,
>>>> + size_t size, size_t offset)
>>>> {
>>>> struct nvme_command c = { };
>>>> unsigned long dwlen = size / 4 - 1;
>>>> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
>>>> index f7135659f918..a1796241040f 100644
>>>> --- a/drivers/nvme/host/lightnvm.c
>>>> +++ b/drivers/nvme/host/lightnvm.c
>>>> @@ -35,6 +35,10 @@ enum nvme_nvm_admin_opcode {
>>>> nvme_nvm_admin_set_bb_tbl = 0xf1,
>>>> };
>>>> +enum nvme_nvm_log_page {
>>>> + NVME_NVM_LOG_REPORT_CHUNK = 0xca,
>>>> +};
>>>> +
>>>> struct nvme_nvm_ph_rw {
>>>> __u8 opcode;
>>>> __u8 flags;
>>>> @@ -236,6 +240,16 @@ struct nvme_nvm_id20 {
>>>> __u8 vs[1024];
>>>> };
>>>> +struct nvme_nvm_chk_meta {
>>>> + __u8 state;
>>>> + __u8 type;
>>>> + __u8 wi;
>>>> + __u8 rsvd[5];
>>>> + __le64 slba;
>>>> + __le64 cnlb;
>>>> + __le64 wp;
>>>> +};
>>>> +
>>>> /*
>>>> * Check we didn't inadvertently grow the command struct
>>>> */
>>>> @@ -252,6 +266,9 @@ static inline void _nvme_nvm_check_size(void)
>>>> BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64);
>>>> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8);
>>>> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
>>>> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != 32);
>>>> + BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) !=
>>>> + sizeof(struct nvm_chk_meta));
>>>> }
>>>> static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
>>>> @@ -555,6 +572,61 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas,
>>>> return ret;
>>>> }
>>>> +/*
>>>> + * Expect the lba in device format
>>>> + */
>>>> +static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
>>>> + struct nvm_chk_meta *meta,
>>>> + sector_t slba, int nchks)
>>>> +{
>>>> + struct nvm_geo *geo = &ndev->geo;
>>>> + struct nvme_ns *ns = ndev->q->queuedata;
>>>> + struct nvme_ctrl *ctrl = ns->ctrl;
>>>> + struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta;
>>>> + struct ppa_addr ppa;
>>>> + size_t left = nchks * sizeof(struct nvme_nvm_chk_meta);
>>>> + size_t log_pos, offset, len;
>>>> + int ret, i;
>>>> +
>>>> + /* Normalize lba address space to obtain log offset */
>>>> + ppa.ppa = slba;
>>>> + ppa = dev_to_generic_addr(ndev, ppa);
>>>> +
>>>> + log_pos = ppa.m.chk;
>>>> + log_pos += ppa.m.pu * geo->num_chk;
>>>> + log_pos += ppa.m.grp * geo->num_lun * geo->num_chk;
>>>
>>> Why is this done?
>> The log page does not map to the lba space. You need to convert it to
>> get one chunk at a time in the format.
>> GRP:PU:CHK
>> I can see why taking a lba as argument is better than a ppa, since users
>> might use the lbas directly, but the conversion needs to be done
>> somewhere.
>
> Good point. I guess this is clash between the two APIs. Chunk metadata
> being laid out sequentially, while the address space is sparse.

Exactly.

> I'm good with the conversion being in the fn.

Cool. I think it is good here too, as it hides the ppa format from the
upper layers. It requires a double conversion from pblk, but it is not
on the fast path anyway...

Javier


Attachments:
signature.asc (849.00 B)
Message signed with OpenPGP

2018-03-02 11:17:50

by Javier González

[permalink] [raw]
Subject: Re: [PATCH 01/15] lightnvm: simplify geometry structure.

> On 1 Mar 2018, at 11.22, Matias Bjørling <[email protected]> wrote:
>
> On 02/28/2018 04:49 PM, Javier González wrote:
>> Currently, the device geometry is stored redundantly in the nvm_id and
>> nvm_geo structures at a device level. Moreover, when instantiating
>> targets on a specific number of LUNs, these structures are replicated
>> and manually modified to fit the instance channel and LUN partitioning.
>> Instead, create a generic geometry around nvm_geo, which can be used by
>> (i) the underlying device to describe the geometry of the whole device,
>> and (ii) instances to describe their geometry independently.
>> Signed-off-by: Javier González <[email protected]>
>> ---
>> drivers/lightnvm/core.c | 70 +++-----
>> drivers/lightnvm/pblk-core.c | 16 +-
>> drivers/lightnvm/pblk-gc.c | 2 +-
>> drivers/lightnvm/pblk-init.c | 119 +++++++-------
>> drivers/lightnvm/pblk-read.c | 2 +-
>> drivers/lightnvm/pblk-recovery.c | 14 +-
>> drivers/lightnvm/pblk-rl.c | 2 +-
>> drivers/lightnvm/pblk-sysfs.c | 39 +++--
>> drivers/lightnvm/pblk-write.c | 2 +-
>> drivers/lightnvm/pblk.h | 87 +++++-----
>> drivers/nvme/host/lightnvm.c | 341 +++++++++++++++++++++++----------------
>> include/linux/lightnvm.h | 200 +++++++++++------------
>> 12 files changed, 465 insertions(+), 429 deletions(-)
>> diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
>> index 19c46ebb1b91..9a417d9cdf0c 100644
>> --- a/drivers/lightnvm/core.c
>> +++ b/drivers/lightnvm/core.c
>> @@ -155,7 +155,7 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
>> int blun = lun_begin % dev->geo.nr_luns;
>> int lunid = 0;
>> int lun_balanced = 1;
>> - int prev_nr_luns;
>> + int sec_per_lun, prev_nr_luns;
>> int i, j;
>> nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1;
>> @@ -215,18 +215,23 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
>> if (!tgt_dev)
>> goto err_ch;
>> + /* Inherit device geometry from parent */
>> memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo));
>> +
>> /* Target device only owns a portion of the physical device */
>> tgt_dev->geo.nr_chnls = nr_chnls;
>> - tgt_dev->geo.all_luns = nr_luns;
>> tgt_dev->geo.nr_luns = (lun_balanced) ? prev_nr_luns : -1;
>> + tgt_dev->geo.all_luns = nr_luns;
>> + tgt_dev->geo.all_chunks = nr_luns * dev->geo.nr_chks;
>> +
>> tgt_dev->geo.op = op;
>> - tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun;
>> +
>> + sec_per_lun = dev->geo.clba * dev->geo.nr_chks;
>> + tgt_dev->geo.total_secs = nr_luns * sec_per_lun;
>> +
>> tgt_dev->q = dev->q;
>> tgt_dev->map = dev_map;
>> tgt_dev->luns = luns;
>> - memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id));
>> -
>> tgt_dev->parent = dev;
>> return tgt_dev;
>> @@ -296,8 +301,6 @@ static int __nvm_config_simple(struct nvm_dev *dev,
>> static int __nvm_config_extended(struct nvm_dev *dev,
>> struct nvm_ioctl_create_extended *e)
>> {
>> - struct nvm_geo *geo = &dev->geo;
>> -
>> if (e->lun_begin == 0xFFFF && e->lun_end == 0xFFFF) {
>> e->lun_begin = 0;
>> e->lun_end = dev->geo.all_luns - 1;
>> @@ -311,7 +314,7 @@ static int __nvm_config_extended(struct nvm_dev *dev,
>> return -EINVAL;
>> }
>> - return nvm_config_check_luns(geo, e->lun_begin, e->lun_end);
>> + return nvm_config_check_luns(&dev->geo, e->lun_begin, e->lun_end);
>> }
>> static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
>> @@ -406,7 +409,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
>> tqueue->queuedata = targetdata;
>> blk_queue_max_hw_sectors(tqueue,
>> - (dev->geo.sec_size >> 9) * NVM_MAX_VLBA);
>> + (dev->geo.csecs >> 9) * NVM_MAX_VLBA);
>> set_capacity(tdisk, tt->capacity(targetdata));
>> add_disk(tdisk);
>> @@ -841,40 +844,9 @@ EXPORT_SYMBOL(nvm_get_tgt_bb_tbl);
>> static int nvm_core_init(struct nvm_dev *dev)
>> {
>> - struct nvm_id *id = &dev->identity;
>> struct nvm_geo *geo = &dev->geo;
>> int ret;
>> - memcpy(&geo->ppaf, &id->ppaf, sizeof(struct nvm_addr_format));
>> -
>> - if (id->mtype != 0) {
>> - pr_err("nvm: memory type not supported\n");
>> - return -EINVAL;
>> - }
>> -
>> - /* Whole device values */
>> - geo->nr_chnls = id->num_ch;
>> - geo->nr_luns = id->num_lun;
>> -
>> - /* Generic device geometry values */
>> - geo->ws_min = id->ws_min;
>> - geo->ws_opt = id->ws_opt;
>> - geo->ws_seq = id->ws_seq;
>> - geo->ws_per_chk = id->ws_per_chk;
>> - geo->nr_chks = id->num_chk;
>> - geo->mccap = id->mccap;
>> -
>> - geo->sec_per_chk = id->clba;
>> - geo->sec_per_lun = geo->sec_per_chk * geo->nr_chks;
>> - geo->all_luns = geo->nr_luns * geo->nr_chnls;
>> -
>> - /* 1.2 spec device geometry values */
>> - geo->plane_mode = 1 << geo->ws_seq;
>> - geo->nr_planes = geo->ws_opt / geo->ws_min;
>> - geo->sec_per_pg = geo->ws_min;
>> - geo->sec_per_pl = geo->sec_per_pg * geo->nr_planes;
>> -
>> - dev->total_secs = geo->all_luns * geo->sec_per_lun;
>> dev->lun_map = kcalloc(BITS_TO_LONGS(geo->all_luns),
>> sizeof(unsigned long), GFP_KERNEL);
>> if (!dev->lun_map)
>> @@ -913,16 +885,14 @@ static int nvm_init(struct nvm_dev *dev)
>> struct nvm_geo *geo = &dev->geo;
>> int ret = -EINVAL;
>> - if (dev->ops->identity(dev, &dev->identity)) {
>> + if (dev->ops->identity(dev)) {
>> pr_err("nvm: device could not be identified\n");
>> goto err;
>> }
>> - if (dev->identity.ver_id != 1 && dev->identity.ver_id != 2) {
>> - pr_err("nvm: device ver_id %d not supported by kernel.\n",
>> - dev->identity.ver_id);
>> - goto err;
>> - }
>> + pr_debug("nvm: ver:%u nvm_vendor:%x\n",
>> + geo->ver_id,
>> + geo->vmnt);
>> ret = nvm_core_init(dev);
>> if (ret) {
>> @@ -930,10 +900,10 @@ static int nvm_init(struct nvm_dev *dev)
>> goto err;
>> }
>> - pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
>> - dev->name, geo->sec_per_pg, geo->nr_planes,
>> - geo->ws_per_chk, geo->nr_chks,
>> - geo->all_luns, geo->nr_chnls);
>> + pr_info("nvm: registered %s [%u/%u/%u/%u/%u]\n",
>> + dev->name, geo->ws_min, geo->ws_opt,
>> + geo->nr_chks, geo->all_luns,
>> + geo->nr_chnls);
>> return 0;
>> err:
>> pr_err("nvm: failed to initialize nvm\n");
>> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
>> index 8848443a0721..169589ddd457 100644
>> --- a/drivers/lightnvm/pblk-core.c
>> +++ b/drivers/lightnvm/pblk-core.c
>> @@ -613,7 +613,7 @@ static int pblk_line_submit_emeta_io(struct pblk *pblk, struct pblk_line *line,
>> memset(&rqd, 0, sizeof(struct nvm_rq));
>> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
>> - rq_len = rq_ppas * geo->sec_size;
>> + rq_len = rq_ppas * geo->csecs;
>> bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len,
>> l_mg->emeta_alloc_type, GFP_KERNEL);
>> @@ -722,7 +722,7 @@ u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line)
>> if (bit >= lm->blk_per_line)
>> return -1;
>> - return bit * geo->sec_per_pl;
>> + return bit * geo->ws_opt;
>> }
>> static int pblk_line_submit_smeta_io(struct pblk *pblk, struct pblk_line *line,
>> @@ -1035,19 +1035,19 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
>> /* Capture bad block information on line mapping bitmaps */
>> while ((bit = find_next_bit(line->blk_bitmap, lm->blk_per_line,
>> bit + 1)) < lm->blk_per_line) {
>> - off = bit * geo->sec_per_pl;
>> + off = bit * geo->ws_opt;
>> bitmap_shift_left(l_mg->bb_aux, l_mg->bb_template, off,
>> lm->sec_per_line);
>> bitmap_or(line->map_bitmap, line->map_bitmap, l_mg->bb_aux,
>> lm->sec_per_line);
>> - line->sec_in_line -= geo->sec_per_chk;
>> + line->sec_in_line -= geo->clba;
>> if (bit >= lm->emeta_bb)
>> nr_bb++;
>> }
>> /* Mark smeta metadata sectors as bad sectors */
>> bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line);
>> - off = bit * geo->sec_per_pl;
>> + off = bit * geo->ws_opt;
>> bitmap_set(line->map_bitmap, off, lm->smeta_sec);
>> line->sec_in_line -= lm->smeta_sec;
>> line->smeta_ssec = off;
>> @@ -1066,10 +1066,10 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
>> emeta_secs = lm->emeta_sec[0];
>> off = lm->sec_per_line;
>> while (emeta_secs) {
>> - off -= geo->sec_per_pl;
>> + off -= geo->ws_opt;
>> if (!test_bit(off, line->invalid_bitmap)) {
>> - bitmap_set(line->invalid_bitmap, off, geo->sec_per_pl);
>> - emeta_secs -= geo->sec_per_pl;
>> + bitmap_set(line->invalid_bitmap, off, geo->ws_opt);
>> + emeta_secs -= geo->ws_opt;
>> }
>> }
>> diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c
>> index 320f99af99e9..6851a5c67189 100644
>> --- a/drivers/lightnvm/pblk-gc.c
>> +++ b/drivers/lightnvm/pblk-gc.c
>> @@ -88,7 +88,7 @@ static void pblk_gc_line_ws(struct work_struct *work)
>> up(&gc->gc_sem);
>> - gc_rq->data = vmalloc(gc_rq->nr_secs * geo->sec_size);
>> + gc_rq->data = vmalloc(gc_rq->nr_secs * geo->csecs);
>> if (!gc_rq->data) {
>> pr_err("pblk: could not GC line:%d (%d/%d)\n",
>> line->id, *line->vsc, gc_rq->nr_secs);
>> diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
>> index 25fc70ca07f7..9b5ee05c3028 100644
>> --- a/drivers/lightnvm/pblk-init.c
>> +++ b/drivers/lightnvm/pblk-init.c
>> @@ -146,7 +146,7 @@ static int pblk_rwb_init(struct pblk *pblk)
>> return -ENOMEM;
>> power_size = get_count_order(nr_entries);
>> - power_seg_sz = get_count_order(geo->sec_size);
>> + power_seg_sz = get_count_order(geo->csecs);
>> return pblk_rb_init(&pblk->rwb, entries, power_size, power_seg_sz);
>> }
>> @@ -154,11 +154,11 @@ static int pblk_rwb_init(struct pblk *pblk)
>> /* Minimum pages needed within a lun */
>> #define ADDR_POOL_SIZE 64
>> -static int pblk_set_ppaf(struct pblk *pblk)
>> +static int pblk_set_addrf_12(struct nvm_geo *geo,
>> + struct nvm_addr_format_12 *dst)
>> {
>> - struct nvm_tgt_dev *dev = pblk->dev;
>> - struct nvm_geo *geo = &dev->geo;
>> - struct nvm_addr_format ppaf = geo->ppaf;
>> + struct nvm_addr_format_12 *src =
>> + (struct nvm_addr_format_12 *)&geo->addrf;
>> int power_len;
>> /* Re-calculate channel and lun format to adapt to configuration */
>> @@ -167,34 +167,50 @@ static int pblk_set_ppaf(struct pblk *pblk)
>> pr_err("pblk: supports only power-of-two channel config.\n");
>> return -EINVAL;
>> }
>> - ppaf.ch_len = power_len;
>> + dst->ch_len = power_len;
>> power_len = get_count_order(geo->nr_luns);
>> if (1 << power_len != geo->nr_luns) {
>> pr_err("pblk: supports only power-of-two LUN config.\n");
>> return -EINVAL;
>> }
>> - ppaf.lun_len = power_len;
>> + dst->lun_len = power_len;
>> - pblk->ppaf.sec_offset = 0;
>> - pblk->ppaf.pln_offset = ppaf.sect_len;
>> - pblk->ppaf.ch_offset = pblk->ppaf.pln_offset + ppaf.pln_len;
>> - pblk->ppaf.lun_offset = pblk->ppaf.ch_offset + ppaf.ch_len;
>> - pblk->ppaf.pg_offset = pblk->ppaf.lun_offset + ppaf.lun_len;
>> - pblk->ppaf.blk_offset = pblk->ppaf.pg_offset + ppaf.pg_len;
>> - pblk->ppaf.sec_mask = (1ULL << ppaf.sect_len) - 1;
>> - pblk->ppaf.pln_mask = ((1ULL << ppaf.pln_len) - 1) <<
>> - pblk->ppaf.pln_offset;
>> - pblk->ppaf.ch_mask = ((1ULL << ppaf.ch_len) - 1) <<
>> - pblk->ppaf.ch_offset;
>> - pblk->ppaf.lun_mask = ((1ULL << ppaf.lun_len) - 1) <<
>> - pblk->ppaf.lun_offset;
>> - pblk->ppaf.pg_mask = ((1ULL << ppaf.pg_len) - 1) <<
>> - pblk->ppaf.pg_offset;
>> - pblk->ppaf.blk_mask = ((1ULL << ppaf.blk_len) - 1) <<
>> - pblk->ppaf.blk_offset;
>> + dst->blk_len = src->blk_len;
>> + dst->pg_len = src->pg_len;
>> + dst->pln_len = src->pln_len;
>> + dst->sect_len = src->sect_len;
>> - pblk->ppaf_bitsize = pblk->ppaf.blk_offset + ppaf.blk_len;
>> + dst->sect_offset = 0;
>> + dst->pln_offset = dst->sect_len;
>> + dst->ch_offset = dst->pln_offset + dst->pln_len;
>> + dst->lun_offset = dst->ch_offset + dst->ch_len;
>> + dst->pg_offset = dst->lun_offset + dst->lun_len;
>> + dst->blk_offset = dst->pg_offset + dst->pg_len;
>> +
>> + dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
>> + dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
>> + dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
>> + dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
>> + dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
>> + dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
>> +
>> + return dst->blk_offset + src->blk_len;
>> +}
>> +
>> +static int pblk_set_ppaf(struct pblk *pblk)
>> +{
>> + struct nvm_tgt_dev *dev = pblk->dev;
>> + struct nvm_geo *geo = &dev->geo;
>> + int mod;
>> +
>> + div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
>> + if (mod) {
>> + pr_err("pblk: bad configuration of sectors/pages\n");
>> + return -EINVAL;
>> + }
>> +
>> + pblk->ppaf_bitsize = pblk_set_addrf_12(geo, (void *)&pblk->ppaf);
>> return 0;
>> }
>> @@ -253,8 +269,7 @@ static int pblk_core_init(struct pblk *pblk)
>> struct nvm_tgt_dev *dev = pblk->dev;
>> struct nvm_geo *geo = &dev->geo;
>> - pblk->pgs_in_buffer = NVM_MEM_PAGE_WRITE * geo->sec_per_pg *
>> - geo->nr_planes * geo->all_luns;
>> + pblk->pgs_in_buffer = geo->mw_cunits * geo->all_luns;
>> if (pblk_init_global_caches(pblk))
>> return -ENOMEM;
>> @@ -552,18 +567,18 @@ static unsigned int calc_emeta_len(struct pblk *pblk)
>> /* Round to sector size so that lba_list starts on its own sector */
>> lm->emeta_sec[1] = DIV_ROUND_UP(
>> sizeof(struct line_emeta) + lm->blk_bitmap_len +
>> - sizeof(struct wa_counters), geo->sec_size);
>> - lm->emeta_len[1] = lm->emeta_sec[1] * geo->sec_size;
>> + sizeof(struct wa_counters), geo->csecs);
>> + lm->emeta_len[1] = lm->emeta_sec[1] * geo->csecs;
>> /* Round to sector size so that vsc_list starts on its own sector */
>> lm->dsec_per_line = lm->sec_per_line - lm->emeta_sec[0];
>> lm->emeta_sec[2] = DIV_ROUND_UP(lm->dsec_per_line * sizeof(u64),
>> - geo->sec_size);
>> - lm->emeta_len[2] = lm->emeta_sec[2] * geo->sec_size;
>> + geo->csecs);
>> + lm->emeta_len[2] = lm->emeta_sec[2] * geo->csecs;
>> lm->emeta_sec[3] = DIV_ROUND_UP(l_mg->nr_lines * sizeof(u32),
>> - geo->sec_size);
>> - lm->emeta_len[3] = lm->emeta_sec[3] * geo->sec_size;
>> + geo->csecs);
>> + lm->emeta_len[3] = lm->emeta_sec[3] * geo->csecs;
>> lm->vsc_list_len = l_mg->nr_lines * sizeof(u32);
>> @@ -594,13 +609,13 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
>> * on user capacity consider only provisioned blocks
>> */
>> pblk->rl.total_blocks = nr_free_blks;
>> - pblk->rl.nr_secs = nr_free_blks * geo->sec_per_chk;
>> + pblk->rl.nr_secs = nr_free_blks * geo->clba;
>> /* Consider sectors used for metadata */
>> sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
>> - blk_meta = DIV_ROUND_UP(sec_meta, geo->sec_per_chk);
>> + blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);
>> - pblk->capacity = (provisioned - blk_meta) * geo->sec_per_chk;
>> + pblk->capacity = (provisioned - blk_meta) * geo->clba;
>> atomic_set(&pblk->rl.free_blocks, nr_free_blks);
>> atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
>> @@ -711,10 +726,10 @@ static int pblk_lines_init(struct pblk *pblk)
>> void *chunk_log;
>> unsigned int smeta_len, emeta_len;
>> long nr_bad_blks = 0, nr_free_blks = 0;
>> - int bb_distance, max_write_ppas, mod;
>> + int bb_distance, max_write_ppas;
>> int i, ret;
>> - pblk->min_write_pgs = geo->sec_per_pl * (geo->sec_size / PAGE_SIZE);
>> + pblk->min_write_pgs = geo->ws_opt * (geo->csecs / PAGE_SIZE);
>> max_write_ppas = pblk->min_write_pgs * geo->all_luns;
>> pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA);
>> pblk_set_sec_per_write(pblk, pblk->min_write_pgs);
>> @@ -725,19 +740,13 @@ static int pblk_lines_init(struct pblk *pblk)
>> return -EINVAL;
>> }
>> - div_u64_rem(geo->sec_per_chk, pblk->min_write_pgs, &mod);
>> - if (mod) {
>> - pr_err("pblk: bad configuration of sectors/pages\n");
>> - return -EINVAL;
>> - }
>> -
>> l_mg->nr_lines = geo->nr_chks;
>> l_mg->log_line = l_mg->data_line = NULL;
>> l_mg->l_seq_nr = l_mg->d_seq_nr = 0;
>> l_mg->nr_free_lines = 0;
>> bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES);
>> - lm->sec_per_line = geo->sec_per_chk * geo->all_luns;
>> + lm->sec_per_line = geo->clba * geo->all_luns;
>> lm->blk_per_line = geo->all_luns;
>> lm->blk_bitmap_len = BITS_TO_LONGS(geo->all_luns) * sizeof(long);
>> lm->sec_bitmap_len = BITS_TO_LONGS(lm->sec_per_line) * sizeof(long);
>> @@ -751,8 +760,8 @@ static int pblk_lines_init(struct pblk *pblk)
>> */
>> i = 1;
>> add_smeta_page:
>> - lm->smeta_sec = i * geo->sec_per_pl;
>> - lm->smeta_len = lm->smeta_sec * geo->sec_size;
>> + lm->smeta_sec = i * geo->ws_opt;
>> + lm->smeta_len = lm->smeta_sec * geo->csecs;
>> smeta_len = sizeof(struct line_smeta) + lm->lun_bitmap_len;
>> if (smeta_len > lm->smeta_len) {
>> @@ -765,8 +774,8 @@ static int pblk_lines_init(struct pblk *pblk)
>> */
>> i = 1;
>> add_emeta_page:
>> - lm->emeta_sec[0] = i * geo->sec_per_pl;
>> - lm->emeta_len[0] = lm->emeta_sec[0] * geo->sec_size;
>> + lm->emeta_sec[0] = i * geo->ws_opt;
>> + lm->emeta_len[0] = lm->emeta_sec[0] * geo->csecs;
>> emeta_len = calc_emeta_len(pblk);
>> if (emeta_len > lm->emeta_len[0]) {
>> @@ -779,7 +788,7 @@ static int pblk_lines_init(struct pblk *pblk)
>> lm->min_blk_line = 1;
>> if (geo->all_luns > 1)
>> lm->min_blk_line += DIV_ROUND_UP(lm->smeta_sec +
>> - lm->emeta_sec[0], geo->sec_per_chk);
>> + lm->emeta_sec[0], geo->clba);
>> if (lm->min_blk_line > lm->blk_per_line) {
>> pr_err("pblk: config. not supported. Min. LUN in line:%d\n",
>> @@ -803,9 +812,9 @@ static int pblk_lines_init(struct pblk *pblk)
>> goto fail_free_bb_template;
>> }
>> - bb_distance = (geo->all_luns) * geo->sec_per_pl;
>> + bb_distance = (geo->all_luns) * geo->ws_opt;
>> for (i = 0; i < lm->sec_per_line; i += bb_distance)
>> - bitmap_set(l_mg->bb_template, i, geo->sec_per_pl);
>> + bitmap_set(l_mg->bb_template, i, geo->ws_opt);
>> INIT_LIST_HEAD(&l_mg->free_list);
>> INIT_LIST_HEAD(&l_mg->corrupt_list);
>> @@ -982,9 +991,9 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
>> struct pblk *pblk;
>> int ret;
>> - if (dev->identity.dom & NVM_RSP_L2P) {
>> + if (dev->geo.dom & NVM_RSP_L2P) {
>> pr_err("pblk: host-side L2P table not supported. (%x)\n",
>> - dev->identity.dom);
>> + dev->geo.dom);
>> return ERR_PTR(-EINVAL);
>> }
>> @@ -1092,7 +1101,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
>> blk_queue_write_cache(tqueue, true, false);
>> - tqueue->limits.discard_granularity = geo->sec_per_chk * geo->sec_size;
>> + tqueue->limits.discard_granularity = geo->clba * geo->csecs;
>> tqueue->limits.discard_alignment = 0;
>> blk_queue_max_discard_sectors(tqueue, UINT_MAX >> 9);
>> queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, tqueue);
>> diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
>> index 2f761283f43e..9eee10f69df0 100644
>> --- a/drivers/lightnvm/pblk-read.c
>> +++ b/drivers/lightnvm/pblk-read.c
>> @@ -563,7 +563,7 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
>> if (!(gc_rq->secs_to_gc))
>> goto out;
>> - data_len = (gc_rq->secs_to_gc) * geo->sec_size;
>> + data_len = (gc_rq->secs_to_gc) * geo->csecs;
>> bio = pblk_bio_map_addr(pblk, gc_rq->data, gc_rq->secs_to_gc, data_len,
>> PBLK_VMALLOC_META, GFP_KERNEL);
>> if (IS_ERR(bio)) {
>> diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
>> index aaab9a5c17cc..26356429dc72 100644
>> --- a/drivers/lightnvm/pblk-recovery.c
>> +++ b/drivers/lightnvm/pblk-recovery.c
>> @@ -184,7 +184,7 @@ static int pblk_calc_sec_in_line(struct pblk *pblk, struct pblk_line *line)
>> int nr_bb = bitmap_weight(line->blk_bitmap, lm->blk_per_line);
>> return lm->sec_per_line - lm->smeta_sec - lm->emeta_sec[0] -
>> - nr_bb * geo->sec_per_chk;
>> + nr_bb * geo->clba;
>> }
>> struct pblk_recov_alloc {
>> @@ -232,7 +232,7 @@ static int pblk_recov_read_oob(struct pblk *pblk, struct pblk_line *line,
>> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
>> if (!rq_ppas)
>> rq_ppas = pblk->min_write_pgs;
>> - rq_len = rq_ppas * geo->sec_size;
>> + rq_len = rq_ppas * geo->csecs;
>> bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
>> if (IS_ERR(bio))
>> @@ -351,7 +351,7 @@ static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
>> if (!pad_rq)
>> return -ENOMEM;
>> - data = vzalloc(pblk->max_write_pgs * geo->sec_size);
>> + data = vzalloc(pblk->max_write_pgs * geo->csecs);
>> if (!data) {
>> ret = -ENOMEM;
>> goto free_rq;
>> @@ -368,7 +368,7 @@ static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
>> goto fail_free_pad;
>> }
>> - rq_len = rq_ppas * geo->sec_size;
>> + rq_len = rq_ppas * geo->csecs;
>> meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list);
>> if (!meta_list) {
>> @@ -509,7 +509,7 @@ static int pblk_recov_scan_all_oob(struct pblk *pblk, struct pblk_line *line,
>> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
>> if (!rq_ppas)
>> rq_ppas = pblk->min_write_pgs;
>> - rq_len = rq_ppas * geo->sec_size;
>> + rq_len = rq_ppas * geo->csecs;
>> bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
>> if (IS_ERR(bio))
>> @@ -640,7 +640,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
>> rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
>> if (!rq_ppas)
>> rq_ppas = pblk->min_write_pgs;
>> - rq_len = rq_ppas * geo->sec_size;
>> + rq_len = rq_ppas * geo->csecs;
>> bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
>> if (IS_ERR(bio))
>> @@ -745,7 +745,7 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line)
>> ppa_list = (void *)(meta_list) + pblk_dma_meta_size;
>> dma_ppa_list = dma_meta_list + pblk_dma_meta_size;
>> - data = kcalloc(pblk->max_write_pgs, geo->sec_size, GFP_KERNEL);
>> + data = kcalloc(pblk->max_write_pgs, geo->csecs, GFP_KERNEL);
>> if (!data) {
>> ret = -ENOMEM;
>> goto free_meta_list;
>> diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c
>> index 0d457b162f23..883a7113b19d 100644
>> --- a/drivers/lightnvm/pblk-rl.c
>> +++ b/drivers/lightnvm/pblk-rl.c
>> @@ -200,7 +200,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)
>> /* Consider sectors used for metadata */
>> sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
>> - blk_meta = DIV_ROUND_UP(sec_meta, geo->sec_per_chk);
>> + blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);
>> rl->high = pblk->op_blks - blk_meta - lm->blk_per_line;
>> rl->high_pw = get_count_order(rl->high);
>> diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
>> index 1680ce0a828d..33199c6af267 100644
>> --- a/drivers/lightnvm/pblk-sysfs.c
>> +++ b/drivers/lightnvm/pblk-sysfs.c
>> @@ -113,26 +113,31 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
>> {
>> struct nvm_tgt_dev *dev = pblk->dev;
>> struct nvm_geo *geo = &dev->geo;
>> + struct nvm_addr_format_12 *ppaf;
>> + struct nvm_addr_format_12 *geo_ppaf;
>> ssize_t sz = 0;
>> - sz = snprintf(page, PAGE_SIZE - sz,
>> - "g:(b:%d)blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
>> - pblk->ppaf_bitsize,
>> - pblk->ppaf.blk_offset, geo->ppaf.blk_len,
>> - pblk->ppaf.pg_offset, geo->ppaf.pg_len,
>> - pblk->ppaf.lun_offset, geo->ppaf.lun_len,
>> - pblk->ppaf.ch_offset, geo->ppaf.ch_len,
>> - pblk->ppaf.pln_offset, geo->ppaf.pln_len,
>> - pblk->ppaf.sec_offset, geo->ppaf.sect_len);
>> + ppaf = (struct nvm_addr_format_12 *)&pblk->ppaf;
>> + geo_ppaf = (struct nvm_addr_format_12 *)&geo->addrf;
>> +
>> + sz = snprintf(page, PAGE_SIZE,
>> + "pblk:(s:%d)ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
>> + pblk->ppaf_bitsize,
>> + ppaf->ch_offset, ppaf->ch_len,
>> + ppaf->lun_offset, ppaf->lun_len,
>> + ppaf->blk_offset, ppaf->blk_len,
>> + ppaf->pg_offset, ppaf->pg_len,
>> + ppaf->pln_offset, ppaf->pln_len,
>> + ppaf->sect_offset, ppaf->sect_len);
>
> Is it on purpose here that the code breaks user-space by changing the sysfs print format?

Fixed.

>
>> sz += snprintf(page + sz, PAGE_SIZE - sz,
>> - "d:blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
>> - geo->ppaf.blk_offset, geo->ppaf.blk_len,
>> - geo->ppaf.pg_offset, geo->ppaf.pg_len,
>> - geo->ppaf.lun_offset, geo->ppaf.lun_len,
>> - geo->ppaf.ch_offset, geo->ppaf.ch_len,
>> - geo->ppaf.pln_offset, geo->ppaf.pln_len,
>> - geo->ppaf.sect_offset, geo->ppaf.sect_len);
>> + "device:ch:%d/%d,lun:%d/%d,blk:%d/%d,pg:%d/%d,pl:%d/%d,sec:%d/%d\n",
>> + geo_ppaf->ch_offset, geo_ppaf->ch_len,
>> + geo_ppaf->lun_offset, geo_ppaf->lun_len,
>> + geo_ppaf->blk_offset, geo_ppaf->blk_len,
>> + geo_ppaf->pg_offset, geo_ppaf->pg_len,
>> + geo_ppaf->pln_offset, geo_ppaf->pln_len,
>> + geo_ppaf->sect_offset, geo_ppaf->sect_len);
>
> Similarily here.

Fixed.

>
>> return sz;
>> }
>> @@ -288,7 +293,7 @@ static ssize_t pblk_sysfs_lines_info(struct pblk *pblk, char *page)
>> "blk_line:%d, sec_line:%d, sec_blk:%d\n",
>> lm->blk_per_line,
>> lm->sec_per_line,
>> - geo->sec_per_chk);
>> + geo->clba);
>> return sz;
>> }
>> diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c
>> index aae86ed60b98..3e6f1ebd743a 100644
>> --- a/drivers/lightnvm/pblk-write.c
>> +++ b/drivers/lightnvm/pblk-write.c
>> @@ -333,7 +333,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line)
>> m_ctx = nvm_rq_to_pdu(rqd);
>> m_ctx->private = meta_line;
>> - rq_len = rq_ppas * geo->sec_size;
>> + rq_len = rq_ppas * geo->csecs;
>> data = ((void *)emeta->buf) + emeta->mem;
>> bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len,
>> diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
>> index f0309d8172c0..b29c1e6698aa 100644
>> --- a/drivers/lightnvm/pblk.h
>> +++ b/drivers/lightnvm/pblk.h
>> @@ -551,21 +551,6 @@ struct pblk_line_meta {
>> unsigned int meta_distance; /* Distance between data and metadata */
>> };
>> -struct pblk_addr_format {
>> - u64 ch_mask;
>> - u64 lun_mask;
>> - u64 pln_mask;
>> - u64 blk_mask;
>> - u64 pg_mask;
>> - u64 sec_mask;
>> - u8 ch_offset;
>> - u8 lun_offset;
>> - u8 pln_offset;
>> - u8 blk_offset;
>> - u8 pg_offset;
>> - u8 sec_offset;
>> -};
>> -
>> enum {
>> PBLK_STATE_RUNNING = 0,
>> PBLK_STATE_STOPPING = 1,
>> @@ -585,8 +570,8 @@ struct pblk {
>> struct pblk_line_mgmt l_mg; /* Line management */
>> struct pblk_line_meta lm; /* Line metadata */
>> + struct nvm_addr_format ppaf;
>> int ppaf_bitsize;
>> - struct pblk_addr_format ppaf;
>> struct pblk_rb rwb;
>> @@ -941,14 +926,12 @@ static inline int pblk_line_vsc(struct pblk_line *line)
>> return le32_to_cpu(*line->vsc);
>> }
>> -#define NVM_MEM_PAGE_WRITE (8)
>> -
>> static inline int pblk_pad_distance(struct pblk *pblk)
>> {
>> struct nvm_tgt_dev *dev = pblk->dev;
>> struct nvm_geo *geo = &dev->geo;
>> - return NVM_MEM_PAGE_WRITE * geo->all_luns * geo->sec_per_pl;
>> + return geo->mw_cunits * geo->all_luns * geo->ws_opt;
>> }
>> static inline int pblk_ppa_to_line(struct ppa_addr p)
>> @@ -964,15 +947,17 @@ static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
>> static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
>> u64 line_id)
>> {
>> + struct nvm_addr_format_12 *ppaf =
>> + (struct nvm_addr_format_12 *)&pblk->ppaf;
>> struct ppa_addr ppa;
>> ppa.ppa = 0;
>> ppa.g.blk = line_id;
>> - ppa.g.pg = (paddr & pblk->ppaf.pg_mask) >> pblk->ppaf.pg_offset;
>> - ppa.g.lun = (paddr & pblk->ppaf.lun_mask) >> pblk->ppaf.lun_offset;
>> - ppa.g.ch = (paddr & pblk->ppaf.ch_mask) >> pblk->ppaf.ch_offset;
>> - ppa.g.pl = (paddr & pblk->ppaf.pln_mask) >> pblk->ppaf.pln_offset;
>> - ppa.g.sec = (paddr & pblk->ppaf.sec_mask) >> pblk->ppaf.sec_offset;
>> + ppa.g.pg = (paddr & ppaf->pg_mask) >> ppaf->pg_offset;
>> + ppa.g.lun = (paddr & ppaf->lun_mask) >> ppaf->lun_offset;
>> + ppa.g.ch = (paddr & ppaf->ch_mask) >> ppaf->ch_offset;
>> + ppa.g.pl = (paddr & ppaf->pln_mask) >> ppaf->pln_offset;
>> + ppa.g.sec = (paddr & ppaf->sec_mask) >> ppaf->sect_offset;
>> return ppa;
>> }
>> @@ -980,13 +965,15 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
>> static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
>> struct ppa_addr p)
>> {
>> + struct nvm_addr_format_12 *ppaf =
>> + (struct nvm_addr_format_12 *)&pblk->ppaf;
>> u64 paddr;
>> - paddr = (u64)p.g.pg << pblk->ppaf.pg_offset;
>> - paddr |= (u64)p.g.lun << pblk->ppaf.lun_offset;
>> - paddr |= (u64)p.g.ch << pblk->ppaf.ch_offset;
>> - paddr |= (u64)p.g.pl << pblk->ppaf.pln_offset;
>> - paddr |= (u64)p.g.sec << pblk->ppaf.sec_offset;
>> + paddr = (u64)p.g.ch << ppaf->ch_offset;
>> + paddr |= (u64)p.g.lun << ppaf->lun_offset;
>> + paddr |= (u64)p.g.pg << ppaf->pg_offset;
>> + paddr |= (u64)p.g.pl << ppaf->pln_offset;
>> + paddr |= (u64)p.g.sec << ppaf->sect_offset;
>> return paddr;
>> }
>> @@ -1003,18 +990,15 @@ static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
>> ppa64.c.line = ppa32 & ((~0U) >> 1);
>> ppa64.c.is_cached = 1;
>> } else {
>> - ppa64.g.blk = (ppa32 & pblk->ppaf.blk_mask) >>
>> - pblk->ppaf.blk_offset;
>> - ppa64.g.pg = (ppa32 & pblk->ppaf.pg_mask) >>
>> - pblk->ppaf.pg_offset;
>> - ppa64.g.lun = (ppa32 & pblk->ppaf.lun_mask) >>
>> - pblk->ppaf.lun_offset;
>> - ppa64.g.ch = (ppa32 & pblk->ppaf.ch_mask) >>
>> - pblk->ppaf.ch_offset;
>> - ppa64.g.pl = (ppa32 & pblk->ppaf.pln_mask) >>
>> - pblk->ppaf.pln_offset;
>> - ppa64.g.sec = (ppa32 & pblk->ppaf.sec_mask) >>
>> - pblk->ppaf.sec_offset;
>> + struct nvm_addr_format_12 *ppaf =
>> + (struct nvm_addr_format_12 *)&pblk->ppaf;
>> +
>> + ppa64.g.ch = (ppa32 & ppaf->ch_mask) >> ppaf->ch_offset;
>> + ppa64.g.lun = (ppa32 & ppaf->lun_mask) >> ppaf->lun_offset;
>> + ppa64.g.blk = (ppa32 & ppaf->blk_mask) >> ppaf->blk_offset;
>> + ppa64.g.pg = (ppa32 & ppaf->pg_mask) >> ppaf->pg_offset;
>> + ppa64.g.pl = (ppa32 & ppaf->pln_mask) >> ppaf->pln_offset;
>> + ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> ppaf->sect_offset;
>> }
>> return ppa64;
>> @@ -1030,12 +1014,15 @@ static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
>> ppa32 |= ppa64.c.line;
>> ppa32 |= 1U << 31;
>> } else {
>> - ppa32 |= ppa64.g.blk << pblk->ppaf.blk_offset;
>> - ppa32 |= ppa64.g.pg << pblk->ppaf.pg_offset;
>> - ppa32 |= ppa64.g.lun << pblk->ppaf.lun_offset;
>> - ppa32 |= ppa64.g.ch << pblk->ppaf.ch_offset;
>> - ppa32 |= ppa64.g.pl << pblk->ppaf.pln_offset;
>> - ppa32 |= ppa64.g.sec << pblk->ppaf.sec_offset;
>> + struct nvm_addr_format_12 *ppaf =
>> + (struct nvm_addr_format_12 *)&pblk->ppaf;
>> +
>> + ppa32 |= ppa64.g.ch << ppaf->ch_offset;
>> + ppa32 |= ppa64.g.lun << ppaf->lun_offset;
>> + ppa32 |= ppa64.g.blk << ppaf->blk_offset;
>> + ppa32 |= ppa64.g.pg << ppaf->pg_offset;
>> + ppa32 |= ppa64.g.pl << ppaf->pln_offset;
>> + ppa32 |= ppa64.g.sec << ppaf->sect_offset;
>> }
>> return ppa32;
>> @@ -1229,10 +1216,10 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev,
>> if (!ppa->c.is_cached &&
>> ppa->g.ch < geo->nr_chnls &&
>> ppa->g.lun < geo->nr_luns &&
>> - ppa->g.pl < geo->nr_planes &&
>> + ppa->g.pl < geo->num_pln &&
>> ppa->g.blk < geo->nr_chks &&
>> - ppa->g.pg < geo->ws_per_chk &&
>> - ppa->g.sec < geo->sec_per_pg)
>> + ppa->g.pg < geo->num_pg &&
>> + ppa->g.sec < geo->ws_min)
>> continue;
>> print_ppa(ppa, "boundary", i);
>> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
>> index 839c0b96466a..e276ace28c64 100644
>> --- a/drivers/nvme/host/lightnvm.c
>> +++ b/drivers/nvme/host/lightnvm.c
>> @@ -152,8 +152,8 @@ struct nvme_nvm_id12_addrf {
>> __u8 blk_len;
>> __u8 pg_offset;
>> __u8 pg_len;
>> - __u8 sect_offset;
>> - __u8 sect_len;
>> + __u8 sec_offset;
>> + __u8 sec_len;
>> __u8 res[4];
>> } __packed;
>> @@ -254,106 +254,161 @@ static inline void _nvme_nvm_check_size(void)
>> BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
>> }
>> -static int init_grp(struct nvm_id *nvm_id, struct nvme_nvm_id12 *id12)
>> +static void nvme_nvm_set_addr_12(struct nvm_addr_format_12 *dst,
>> + struct nvme_nvm_id12_addrf *src)
>> +{
>> + dst->ch_len = src->ch_len;
>> + dst->lun_len = src->lun_len;
>> + dst->blk_len = src->blk_len;
>> + dst->pg_len = src->pg_len;
>> + dst->pln_len = src->pln_len;
>> + dst->sect_len = src->sec_len;
>> +
>> + dst->ch_offset = src->ch_offset;
>> + dst->lun_offset = src->lun_offset;
>> + dst->blk_offset = src->blk_offset;
>> + dst->pg_offset = src->pg_offset;
>> + dst->pln_offset = src->pln_offset;
>> + dst->sect_offset = src->sec_offset;
>> +
>> + dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
>> + dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
>> + dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
>> + dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
>> + dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
>> + dst->sec_mask = ((1ULL << dst->sect_len) - 1) << dst->sect_offset;
>> +}
>> +
>> +static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
>> + struct nvm_geo *geo)
>> {
>> struct nvme_nvm_id12_grp *src;
>> int sec_per_pg, sec_per_pl, pg_per_blk;
>> - if (id12->cgrps != 1)
>> + if (id->cgrps != 1)
>> return -EINVAL;
>> - src = &id12->grp;
>> + src = &id->grp;
>> - nvm_id->mtype = src->mtype;
>> - nvm_id->fmtype = src->fmtype;
>> + if (src->mtype != 0) {
>> + pr_err("nvm: memory type not supported\n");
>> + return -EINVAL;
>> + }
>> +
>> + geo->ver_id = id->ver_id;
>> +
>> + geo->nr_chnls = src->num_ch;
>> + geo->nr_luns = src->num_lun;
>> + geo->all_luns = geo->nr_chnls * geo->nr_luns;
>> - nvm_id->num_ch = src->num_ch;
>> - nvm_id->num_lun = src->num_lun;
>> + geo->nr_chks = le16_to_cpu(src->num_chk);
>> - nvm_id->num_chk = le16_to_cpu(src->num_chk);
>> - nvm_id->csecs = le16_to_cpu(src->csecs);
>> - nvm_id->sos = le16_to_cpu(src->sos);
>> + geo->csecs = le16_to_cpu(src->csecs);
>> + geo->sos = le16_to_cpu(src->sos);
>> pg_per_blk = le16_to_cpu(src->num_pg);
>> - sec_per_pg = le16_to_cpu(src->fpg_sz) / nvm_id->csecs;
>> + sec_per_pg = le16_to_cpu(src->fpg_sz) / geo->csecs;
>> sec_per_pl = sec_per_pg * src->num_pln;
>> - nvm_id->clba = sec_per_pl * pg_per_blk;
>> - nvm_id->ws_per_chk = pg_per_blk;
>> -
>> - nvm_id->mpos = le32_to_cpu(src->mpos);
>> - nvm_id->cpar = le16_to_cpu(src->cpar);
>> - nvm_id->mccap = le32_to_cpu(src->mccap);
>> -
>> - nvm_id->ws_opt = nvm_id->ws_min = sec_per_pg;
>> - nvm_id->ws_seq = NVM_IO_SNGL_ACCESS;
>> -
>> - if (nvm_id->mpos & 0x020202) {
>> - nvm_id->ws_seq = NVM_IO_DUAL_ACCESS;
>> - nvm_id->ws_opt <<= 1;
>> - } else if (nvm_id->mpos & 0x040404) {
>> - nvm_id->ws_seq = NVM_IO_QUAD_ACCESS;
>> - nvm_id->ws_opt <<= 2;
>> + geo->clba = sec_per_pl * pg_per_blk;
>> +
>> + geo->all_chunks = geo->all_luns * geo->nr_chks;
>> + geo->total_secs = geo->clba * geo->all_chunks;
>> +
>> + geo->ws_min = sec_per_pg;
>> + geo->ws_opt = sec_per_pg;
>> + geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */
>> +
>> + geo->mccap = le32_to_cpu(src->mccap);
>> +
>> + geo->trdt = le32_to_cpu(src->trdt);
>> + geo->trdm = le32_to_cpu(src->trdm);
>> + geo->tprt = le32_to_cpu(src->tprt);
>> + geo->tprm = le32_to_cpu(src->tprm);
>> + geo->tbet = le32_to_cpu(src->tbet);
>> + geo->tbem = le32_to_cpu(src->tbem);
>> +
>> + /* 1.2 compatibility */
>> + geo->vmnt = id->vmnt;
>> + geo->cap = le32_to_cpu(id->cap);
>> + geo->dom = le32_to_cpu(id->dom);
>> +
>> + geo->mtype = src->mtype;
>> + geo->fmtype = src->fmtype;
>> +
>> + geo->cpar = le16_to_cpu(src->cpar);
>> + geo->mpos = le32_to_cpu(src->mpos);
>> +
>> + geo->plane_mode = NVM_PLANE_SINGLE;
>> +
>> + if (geo->mpos & 0x020202) {
>> + geo->plane_mode = NVM_PLANE_DOUBLE;
>> + geo->ws_opt <<= 1;
>> + } else if (geo->mpos & 0x040404) {
>> + geo->plane_mode = NVM_PLANE_QUAD;
>> + geo->ws_opt <<= 2;
>> }
>> - nvm_id->trdt = le32_to_cpu(src->trdt);
>> - nvm_id->trdm = le32_to_cpu(src->trdm);
>> - nvm_id->tprt = le32_to_cpu(src->tprt);
>> - nvm_id->tprm = le32_to_cpu(src->tprm);
>> - nvm_id->tbet = le32_to_cpu(src->tbet);
>> - nvm_id->tbem = le32_to_cpu(src->tbem);
>> -
>> - /* 1.2 compatibility */
>> - nvm_id->num_pln = src->num_pln;
>> - nvm_id->num_pg = le16_to_cpu(src->num_pg);
>> - nvm_id->fpg_sz = le16_to_cpu(src->fpg_sz);
>> + geo->num_pln = src->num_pln;
>> + geo->num_pg = le16_to_cpu(src->num_pg);
>> + geo->fpg_sz = le16_to_cpu(src->fpg_sz);
>> +
>> + nvme_nvm_set_addr_12((struct nvm_addr_format_12 *)&geo->addrf,
>> + &id->ppaf);
>> return 0;
>> }
>> -static int nvme_nvm_setup_12(struct nvm_dev *nvmdev, struct nvm_id *nvm_id,
>> - struct nvme_nvm_id12 *id)
>> +static void nvme_nvm_set_addr_20(struct nvm_addr_format *dst,
>> + struct nvme_nvm_id20_addrf *src)
>> {
>> - nvm_id->ver_id = id->ver_id;
>> - nvm_id->vmnt = id->vmnt;
>> - nvm_id->cap = le32_to_cpu(id->cap);
>> - nvm_id->dom = le32_to_cpu(id->dom);
>> - memcpy(&nvm_id->ppaf, &id->ppaf,
>> - sizeof(struct nvm_addr_format));
>> -
>> - return init_grp(nvm_id, id);
>> + dst->ch_len = src->grp_len;
>> + dst->lun_len = src->pu_len;
>> + dst->chk_len = src->chk_len;
>> + dst->sec_len = src->lba_len;
>> +
>> + dst->sec_offset = 0;
>> + dst->chk_offset = dst->sec_len;
>> + dst->lun_offset = dst->chk_offset + dst->chk_len;
>> + dst->ch_offset = dst->lun_offset + dst->lun_len;
>> +
>> + dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
>> + dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
>> + dst->chk_mask = ((1ULL << dst->chk_len) - 1) << dst->chk_offset;
>> + dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset;
>> }
>> -static int nvme_nvm_setup_20(struct nvm_dev *nvmdev, struct nvm_id *nvm_id,
>> - struct nvme_nvm_id20 *id)
>> +static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
>> + struct nvm_geo *geo)
>> {
>> - nvm_id->ver_id = id->mjr;
>> + geo->ver_id = id->mjr;
>> +
>> + geo->nr_chnls = le16_to_cpu(id->num_grp);
>> + geo->nr_luns = le16_to_cpu(id->num_pu);
>> + geo->all_luns = geo->nr_chnls * geo->nr_luns;
>> - nvm_id->num_ch = le16_to_cpu(id->num_grp);
>> - nvm_id->num_lun = le16_to_cpu(id->num_pu);
>> - nvm_id->num_chk = le32_to_cpu(id->num_chk);
>> - nvm_id->clba = le32_to_cpu(id->clba);
>> + geo->nr_chks = le32_to_cpu(id->num_chk);
>> + geo->clba = le32_to_cpu(id->clba);
>> - nvm_id->ws_min = le32_to_cpu(id->ws_min);
>> - nvm_id->ws_opt = le32_to_cpu(id->ws_opt);
>> - nvm_id->mw_cunits = le32_to_cpu(id->mw_cunits);
>> + geo->all_chunks = geo->all_luns * geo->nr_chks;
>> + geo->total_secs = geo->clba * geo->all_chunks;
>> - nvm_id->trdt = le32_to_cpu(id->trdt);
>> - nvm_id->trdm = le32_to_cpu(id->trdm);
>> - nvm_id->tprt = le32_to_cpu(id->twrt);
>> - nvm_id->tprm = le32_to_cpu(id->twrm);
>> - nvm_id->tbet = le32_to_cpu(id->tcrst);
>> - nvm_id->tbem = le32_to_cpu(id->tcrsm);
>> + geo->ws_min = le32_to_cpu(id->ws_min);
>> + geo->ws_opt = le32_to_cpu(id->ws_opt);
>> + geo->mw_cunits = le32_to_cpu(id->mw_cunits);
>> - /* calculated values */
>> - nvm_id->ws_per_chk = nvm_id->clba / nvm_id->ws_min;
>> + geo->trdt = le32_to_cpu(id->trdt);
>> + geo->trdm = le32_to_cpu(id->trdm);
>> + geo->tprt = le32_to_cpu(id->twrt);
>> + geo->tprm = le32_to_cpu(id->twrm);
>> + geo->tbet = le32_to_cpu(id->tcrst);
>> + geo->tbem = le32_to_cpu(id->tcrsm);
>> - /* 1.2 compatibility */
>> - nvm_id->ws_seq = NVM_IO_SNGL_ACCESS;
>> + nvme_nvm_set_addr_20(&geo->addrf, &id->lbaf);
>> return 0;
>> }
>> -static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
>> +static int nvme_nvm_identity(struct nvm_dev *nvmdev)
>> {
>> struct nvme_ns *ns = nvmdev->q->queuedata;
>> struct nvme_nvm_id12 *id;
>> @@ -380,18 +435,18 @@ static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
>> */
>> switch (id->ver_id) {
>> case 1:
>> - ret = nvme_nvm_setup_12(nvmdev, nvm_id, id);
>> + ret = nvme_nvm_setup_12(id, &nvmdev->geo);
>> break;
>> case 2:
>> - ret = nvme_nvm_setup_20(nvmdev, nvm_id,
>> - (struct nvme_nvm_id20 *)id);
>> + ret = nvme_nvm_setup_20((struct nvme_nvm_id20 *)id,
>> + &nvmdev->geo);
>> break;
>> default:
>> - dev_err(ns->ctrl->device,
>> - "OCSSD revision not supported (%d)\n",
>> - nvm_id->ver_id);
>> + dev_err(ns->ctrl->device, "OCSSD revision not supported (%d)\n",
>> + id->ver_id);
>> ret = -EINVAL;
>> }
>> +
>> out:
>> kfree(id);
>> return ret;
>> @@ -406,7 +461,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
>> struct nvme_ctrl *ctrl = ns->ctrl;
>> struct nvme_nvm_command c = {};
>> struct nvme_nvm_bb_tbl *bb_tbl;
>> - int nr_blks = geo->nr_chks * geo->plane_mode;
>> + int nr_blks = geo->nr_chks * geo->num_pln;
>> int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blks;
>> int ret = 0;
>> @@ -447,7 +502,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
>> goto out;
>> }
>> - memcpy(blks, bb_tbl->blk, geo->nr_chks * geo->plane_mode);
>> + memcpy(blks, bb_tbl->blk, geo->nr_chks * geo->num_pln);
>> out:
>> kfree(bb_tbl);
>> return ret;
>> @@ -815,9 +870,10 @@ int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg)
>> void nvme_nvm_update_nvm_info(struct nvme_ns *ns)
>> {
>> struct nvm_dev *ndev = ns->ndev;
>> + struct nvm_geo *geo = &ndev->geo;
>> - ndev->identity.csecs = ndev->geo.sec_size = 1 << ns->lba_shift;
>> - ndev->identity.sos = ndev->geo.oob_size = ns->ms;
>> + geo->csecs = 1 << ns->lba_shift;
>> + geo->sos = ns->ms;
>> }
>> int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node)
>> @@ -850,23 +906,22 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
>> {
>> struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
>> struct nvm_dev *ndev = ns->ndev;
>> - struct nvm_id *id;
>> + struct nvm_geo *geo = &ndev->geo;
>> struct attribute *attr;
>> if (!ndev)
>> return 0;
>> - id = &ndev->identity;
>> attr = &dattr->attr;
>> if (strcmp(attr->name, "version") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->ver_id);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->ver_id);
>> } else if (strcmp(attr->name, "capabilities") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->cap);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->cap);
>> } else if (strcmp(attr->name, "read_typ") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->trdt);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdt);
>> } else if (strcmp(attr->name, "read_max") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->trdm);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdm);
>> } else {
>> return scnprintf(page,
>> PAGE_SIZE,
>> @@ -875,75 +930,79 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
>> }
>> }
>> +static ssize_t nvm_dev_attr_show_ppaf(struct nvm_addr_format_12 *ppaf,
>> + char *page)
>> +{
>> + return scnprintf(page, PAGE_SIZE,
>> + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
>> + ppaf->ch_offset, ppaf->ch_len,
>> + ppaf->lun_offset, ppaf->lun_len,
>> + ppaf->pln_offset, ppaf->pln_len,
>> + ppaf->blk_offset, ppaf->blk_len,
>> + ppaf->pg_offset, ppaf->pg_len,
>> + ppaf->sect_offset, ppaf->sect_len);
>> +}
>> +
>> static ssize_t nvm_dev_attr_show_12(struct device *dev,
>> struct device_attribute *dattr, char *page)
>> {
>> struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
>> struct nvm_dev *ndev = ns->ndev;
>> - struct nvm_id *id;
>> + struct nvm_geo *geo = &ndev->geo;
>> struct attribute *attr;
>> if (!ndev)
>> return 0;
>> - id = &ndev->identity;
>> attr = &dattr->attr;
>> if (strcmp(attr->name, "vendor_opcode") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->vmnt);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->vmnt);
>> } else if (strcmp(attr->name, "device_mode") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->dom);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->dom);
>> /* kept for compatibility */
>> } else if (strcmp(attr->name, "media_manager") == 0) {
>> return scnprintf(page, PAGE_SIZE, "%s\n", "gennvm");
>> } else if (strcmp(attr->name, "ppa_format") == 0) {
>> - return scnprintf(page, PAGE_SIZE,
>> - "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
>> - id->ppaf.ch_offset, id->ppaf.ch_len,
>> - id->ppaf.lun_offset, id->ppaf.lun_len,
>> - id->ppaf.pln_offset, id->ppaf.pln_len,
>> - id->ppaf.blk_offset, id->ppaf.blk_len,
>> - id->ppaf.pg_offset, id->ppaf.pg_len,
>> - id->ppaf.sect_offset, id->ppaf.sect_len);
>> + return nvm_dev_attr_show_ppaf((void *)&geo->addrf, page);
>
> Why do the code here cast to void *, and not to the address format data structure?
>
> Have you thought about doing the cast directly here, instead of making a function for it?

I like it better to be tight instead of having to break the line for
this. Same point you make below.

>
>> } else if (strcmp(attr->name, "media_type") == 0) { /* u8 */
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->mtype);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->mtype);
>> } else if (strcmp(attr->name, "flash_media_type") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->fmtype);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->fmtype);
>> } else if (strcmp(attr->name, "num_channels") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_ch);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
>> } else if (strcmp(attr->name, "num_luns") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_lun);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
>> } else if (strcmp(attr->name, "num_planes") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_pln);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pln);
>> } else if (strcmp(attr->name, "num_blocks") == 0) { /* u16 */
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_chk);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
>> } else if (strcmp(attr->name, "num_pages") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_pg);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pg);
>> } else if (strcmp(attr->name, "page_size") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->fpg_sz);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->fpg_sz);
>> } else if (strcmp(attr->name, "hw_sector_size") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->csecs);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->csecs);
>> } else if (strcmp(attr->name, "oob_sector_size") == 0) {/* u32 */
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->sos);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->sos);
>> } else if (strcmp(attr->name, "prog_typ") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprt);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt);
>> } else if (strcmp(attr->name, "prog_max") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprm);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm);
>> } else if (strcmp(attr->name, "erase_typ") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbet);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet);
>> } else if (strcmp(attr->name, "erase_max") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbem);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem);
>> } else if (strcmp(attr->name, "multiplane_modes") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "0x%08x\n", id->mpos);
>> + return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mpos);
>> } else if (strcmp(attr->name, "media_capabilities") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "0x%08x\n", id->mccap);
>> + return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mccap);
>> } else if (strcmp(attr->name, "max_phys_secs") == 0) {
>> return scnprintf(page, PAGE_SIZE, "%u\n", NVM_MAX_VLBA);
>> } else {
>> - return scnprintf(page,
>> - PAGE_SIZE,
>> - "Unhandled attr(%s) in `nvm_dev_attr_show_12`\n",
>> - attr->name);
>> + return scnprintf(page, PAGE_SIZE,
>> + "Unhandled attr(%s) in `nvm_dev_attr_show_12`\n",
>> + attr->name);
>> }
>> }
>> @@ -952,42 +1011,40 @@ static ssize_t nvm_dev_attr_show_20(struct device *dev,
>> {
>> struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
>> struct nvm_dev *ndev = ns->ndev;
>> - struct nvm_id *id;
>> + struct nvm_geo *geo = &ndev->geo;
>> struct attribute *attr;
>> if (!ndev)
>> return 0;
>> - id = &ndev->identity;
>> attr = &dattr->attr;
>> if (strcmp(attr->name, "groups") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_ch);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chnls);
>> } else if (strcmp(attr->name, "punits") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_lun);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_luns);
>> } else if (strcmp(attr->name, "chunks") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->num_chk);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->nr_chks);
>> } else if (strcmp(attr->name, "clba") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->clba);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->clba);
>> } else if (strcmp(attr->name, "ws_min") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->ws_min);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_min);
>> } else if (strcmp(attr->name, "ws_opt") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->ws_opt);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_opt);
>> } else if (strcmp(attr->name, "mw_cunits") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->mw_cunits);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->mw_cunits);
>> } else if (strcmp(attr->name, "write_typ") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprt);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt);
>> } else if (strcmp(attr->name, "write_max") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tprm);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm);
>> } else if (strcmp(attr->name, "reset_typ") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbet);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet);
>> } else if (strcmp(attr->name, "reset_max") == 0) {
>> - return scnprintf(page, PAGE_SIZE, "%u\n", id->tbem);
>> + return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem);
>> } else {
>> - return scnprintf(page,
>> - PAGE_SIZE,
>> - "Unhandled attr(%s) in `nvm_dev_attr_show_20`\n",
>> - attr->name);
>> + return scnprintf(page, PAGE_SIZE,
>> + "Unhandled attr(%s) in `nvm_dev_attr_show_20`\n",
>> + attr->name);
>> }
>> }
>> @@ -1106,10 +1163,13 @@ static const struct attribute_group nvm_dev_attr_group_20 = {
>> int nvme_nvm_register_sysfs(struct nvme_ns *ns)
>> {
>> - if (!ns->ndev)
>> + struct nvm_dev *ndev = ns->ndev;
>> + struct nvm_geo *geo = &ndev->geo;
>> +
>> + if (!ndev)
>> return -EINVAL;
>> - switch (ns->ndev->identity.ver_id) {
>> + switch (geo->ver_id) {
>> case 1:
>> return sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
>> &nvm_dev_attr_group_12);
>> @@ -1123,7 +1183,10 @@ int nvme_nvm_register_sysfs(struct nvme_ns *ns)
>> void nvme_nvm_unregister_sysfs(struct nvme_ns *ns)
>> {
>> - switch (ns->ndev->identity.ver_id) {
>> + struct nvm_dev *ndev = ns->ndev;
>> + struct nvm_geo *geo = &ndev->geo;
>> +
>> + switch (geo->ver_id) {
>> case 1:
>> sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
>> &nvm_dev_attr_group_12);
>> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
>> index e55b10573c99..16255fcd5250 100644
>> --- a/include/linux/lightnvm.h
>> +++ b/include/linux/lightnvm.h
>> @@ -50,7 +50,7 @@ struct nvm_id;
>> struct nvm_dev;
>> struct nvm_tgt_dev;
>> -typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
>> +typedef int (nvm_id_fn)(struct nvm_dev *);
>> typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *);
>> typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int);
>> typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
>> @@ -152,62 +152,48 @@ struct nvm_id_lp_tbl {
>> struct nvm_id_lp_mlc mlc;
>> };
>> -struct nvm_addr_format {
>> - u8 ch_offset;
>> +struct nvm_addr_format_12 {
>
> I can see in a couple of places a statement has to be over two lines due
> to the length of writing out nvm_addr_format_12, would it make sense to
> shorthand it to nvm_addrf_12?

Good idea.

>
>> u8 ch_len;
>> - u8 lun_offset;
>> u8 lun_len;
>> - u8 pln_offset;
>> + u8 blk_len;
>> + u8 pg_len;
>> u8 pln_len;
>> + u8 sect_len;
>> +
>> + u8 ch_offset;
>> + u8 lun_offset;
>> u8 blk_offset;
>> - u8 blk_len;
>> u8 pg_offset;
>> - u8 pg_len;
>> + u8 pln_offset;
>> u8 sect_offset;
>> - u8 sect_len;
>> -};
>> -
>> -struct nvm_id {
>> - u8 ver_id;
>> - u8 vmnt;
>> - u32 cap;
>> - u32 dom;
>> -
>> - struct nvm_addr_format ppaf;
>> -
>> - u8 num_ch;
>> - u8 num_lun;
>> - u16 num_chk;
>> - u16 clba;
>> - u16 csecs;
>> - u16 sos;
>> -
>> - u32 ws_min;
>> - u32 ws_opt;
>> - u32 mw_cunits;
>> - u32 trdt;
>> - u32 trdm;
>> - u32 tprt;
>> - u32 tprm;
>> - u32 tbet;
>> - u32 tbem;
>> - u32 mpos;
>> - u32 mccap;
>> - u16 cpar;
>> -
>> - /* calculated values */
>> - u16 ws_seq;
>> - u16 ws_per_chk;
>> -
>> - /* 1.2 compatibility */
>> - u8 mtype;
>> - u8 fmtype;
>> + u64 ch_mask;
>> + u64 lun_mask;
>> + u64 blk_mask;
>> + u64 pg_mask;
>> + u64 pln_mask;
>> + u64 sec_mask;
>> +};
>> - u8 num_pln;
>> - u16 num_pg;
>> - u16 fpg_sz;
>> -} __packed;
>> +struct nvm_addr_format {
>> + u8 ch_len;
>> + u8 lun_len;
>> + u8 chk_len;
>> + u8 sec_len;
>> + u8 rsv_len[2];
>> +
>> + u8 ch_offset;
>> + u8 lun_offset;
>> + u8 chk_offset;
>> + u8 sec_offset;
>> + u8 rsv_off[2];
>> +
>> + u64 ch_mask;
>> + u64 lun_mask;
>> + u64 chk_mask;
>> + u64 sec_mask;
>> + u64 rsv_mask[2];
>> +};
>> struct nvm_target {
>> struct list_head list;
>> @@ -274,36 +260,63 @@ enum {
>> NVM_BLK_ST_BAD = 0x8, /* Bad block */
>> };
>> -
>> -/* Device generic information */
>> +/* Instance geometry */
>> struct nvm_geo {
>> - /* generic geometry */
>> + /* device reported version */
>> + u8 ver_id;
>> +
>> + /* instance specific geometry */
>> int nr_chnls;
>> - int all_luns; /* across channels */
>> - int nr_luns; /* per channel */
>> - int nr_chks; /* per lun */
>> + int nr_luns; /* per channel */
>> - int sec_size;
>> - int oob_size;
>> - int mccap;
>> + /* calculated values */
>> + int all_luns; /* across channels */
>> + int all_chunks; /* across channels */
>> - int sec_per_chk;
>> - int sec_per_lun;
>> + int op; /* over-provision in instance */
>> - int ws_min;
>> - int ws_opt;
>> - int ws_seq;
>> - int ws_per_chk;
>> + sector_t total_secs; /* across channels */
>> - int op;
>> + /* chunk geometry */
>> + u32 nr_chks; /* chunks per lun */
>> + u32 clba; /* sectors per chunk */
>> + u16 csecs; /* sector size */
>> + u16 sos; /* out-of-band area size */
>> - struct nvm_addr_format ppaf;
>> + /* device write constrains */
>> + u32 ws_min; /* minimum write size */
>> + u32 ws_opt; /* optimal write size */
>> + u32 mw_cunits; /* distance required for successful read */
>> - /* Legacy 1.2 specific geometry */
>> - int plane_mode; /* drive device in single, double or quad mode */
>> - int nr_planes;
>> - int sec_per_pg; /* only sectors for a single page */
>> - int sec_per_pl; /* all sectors across planes */
>> + /* device capabilities */
>> + u32 mccap;
>> +
>> + /* device timings */
>> + u32 trdt; /* Avg. Tread (ns) */
>> + u32 trdm; /* Max Tread (ns) */
>> + u32 tprt; /* Avg. Tprog (ns) */
>> + u32 tprm; /* Max Tprog (ns) */
>> + u32 tbet; /* Avg. Terase (ns) */
>> + u32 tbem; /* Max Terase (ns) */
>> +
>> + /* generic address format */
>> + struct nvm_addr_format addrf;
>> +
>> + /* 1.2 compatibility */
>> + u8 vmnt;
>> + u32 cap;
>> + u32 dom;
>> +
>> + u8 mtype;
>> + u8 fmtype;
>> +
>> + u16 cpar;
>> + u32 mpos;
>> +
>> + u8 num_pln;
>> + u8 plane_mode;
>> + u16 num_pg;
>> + u16 fpg_sz;
>> };
>> /* sub-device structure */
>> @@ -314,9 +327,6 @@ struct nvm_tgt_dev {
>> /* Base ppas for target LUNs */
>> struct ppa_addr *luns;
>> - sector_t total_secs;
>> -
>> - struct nvm_id identity;
>> struct request_queue *q;
>> struct nvm_dev *parent;
>> @@ -331,13 +341,9 @@ struct nvm_dev {
>> /* Device information */
>> struct nvm_geo geo;
>> - unsigned long total_secs;
>> -
>> unsigned long *lun_map;
>> void *dma_pool;
>> - struct nvm_id identity;
>> -
>> /* Backend device */
>> struct request_queue *q;
>> char name[DISK_NAME_LEN];
>> @@ -357,14 +363,16 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
>> struct ppa_addr r)
>> {
>> struct nvm_geo *geo = &tgt_dev->geo;
>> + struct nvm_addr_format_12 *ppaf =
>> + (struct nvm_addr_format_12 *)&geo->addrf;
>> struct ppa_addr l;
>> - l.ppa = ((u64)r.g.blk) << geo->ppaf.blk_offset;
>> - l.ppa |= ((u64)r.g.pg) << geo->ppaf.pg_offset;
>> - l.ppa |= ((u64)r.g.sec) << geo->ppaf.sect_offset;
>> - l.ppa |= ((u64)r.g.pl) << geo->ppaf.pln_offset;
>> - l.ppa |= ((u64)r.g.lun) << geo->ppaf.lun_offset;
>> - l.ppa |= ((u64)r.g.ch) << geo->ppaf.ch_offset;
>> + l.ppa = ((u64)r.g.ch) << ppaf->ch_offset;
>> + l.ppa |= ((u64)r.g.lun) << ppaf->lun_offset;
>> + l.ppa |= ((u64)r.g.blk) << ppaf->blk_offset;
>> + l.ppa |= ((u64)r.g.pg) << ppaf->pg_offset;
>> + l.ppa |= ((u64)r.g.pl) << ppaf->pln_offset;
>> + l.ppa |= ((u64)r.g.sec) << ppaf->sect_offset;
>> return l;
>> }
>> @@ -373,24 +381,18 @@ static inline struct ppa_addr dev_to_generic_addr(struct nvm_tgt_dev *tgt_dev,
>> struct ppa_addr r)
>> {
>> struct nvm_geo *geo = &tgt_dev->geo;
>> + struct nvm_addr_format_12 *ppaf =
>> + (struct nvm_addr_format_12 *)&geo->addrf;
>> struct ppa_addr l;
>> l.ppa = 0;
>> - /*
>> - * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc.
>> - */
>> - l.g.blk = (r.ppa >> geo->ppaf.blk_offset) &
>> - (((1 << geo->ppaf.blk_len) - 1));
>> - l.g.pg |= (r.ppa >> geo->ppaf.pg_offset) &
>> - (((1 << geo->ppaf.pg_len) - 1));
>> - l.g.sec |= (r.ppa >> geo->ppaf.sect_offset) &
>> - (((1 << geo->ppaf.sect_len) - 1));
>> - l.g.pl |= (r.ppa >> geo->ppaf.pln_offset) &
>> - (((1 << geo->ppaf.pln_len) - 1));
>> - l.g.lun |= (r.ppa >> geo->ppaf.lun_offset) &
>> - (((1 << geo->ppaf.lun_len) - 1));
>> - l.g.ch |= (r.ppa >> geo->ppaf.ch_offset) &
>> - (((1 << geo->ppaf.ch_len) - 1));
>> +
>> + l.g.ch = (r.ppa & ppaf->ch_mask) >> ppaf->ch_offset;
>> + l.g.lun = (r.ppa & ppaf->lun_mask) >> ppaf->lun_offset;
>> + l.g.blk = (r.ppa & ppaf->blk_mask) >> ppaf->blk_offset;
>> + l.g.pg = (r.ppa & ppaf->pg_mask) >> ppaf->pg_offset;
>> + l.g.pl = (r.ppa & ppaf->pln_mask) >> ppaf->pln_offset;
>> + l.g.sec = (r.ppa & ppaf->sec_mask) >> ppaf->sect_offset;
>> return l;
>> }
>
> Looks good to me,


Attachments:
signature.asc (849.00 B)
Message signed with OpenPGP

2018-03-02 15:12:27

by Javier González

[permalink] [raw]
Subject: Re: [PATCH 02/15] lightnvm: add controller capabilities to 2.0

> On 1 Mar 2018, at 11.33, Matias Bjørling <[email protected]> wrote:
>
> On 02/28/2018 04:49 PM, Javier González wrote:
>> Assign missing mccap value on 2.0 path
>> Signed-off-by: Javier González <[email protected]>
>> ---
>> drivers/nvme/host/lightnvm.c | 4 +++-
>> include/linux/lightnvm.h | 8 +++++---
>> 2 files changed, 8 insertions(+), 4 deletions(-)
>> diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
>> index e276ace28c64..5b2024ebac76 100644
>> --- a/drivers/nvme/host/lightnvm.c
>> +++ b/drivers/nvme/host/lightnvm.c
>> @@ -318,7 +318,7 @@ static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id,
>> geo->ws_opt = sec_per_pg;
>> geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */
>> - geo->mccap = le32_to_cpu(src->mccap);
>> + geo->cap = le32_to_cpu(src->mccap);
>> geo->trdt = le32_to_cpu(src->trdt);
>> geo->trdm = le32_to_cpu(src->trdm);
>> @@ -396,6 +396,8 @@ static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id,
>> geo->ws_opt = le32_to_cpu(id->ws_opt);
>> geo->mw_cunits = le32_to_cpu(id->mw_cunits);
>> + geo->cap = le32_to_cpu(id->mccap);
>> +
>> geo->trdt = le32_to_cpu(id->trdt);
>> geo->trdm = le32_to_cpu(id->trdm);
>> geo->tprt = le32_to_cpu(id->twrt);
>> diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
>> index 16255fcd5250..b9f0d2070de9 100644
>> --- a/include/linux/lightnvm.h
>> +++ b/include/linux/lightnvm.h
>> @@ -288,8 +288,10 @@ struct nvm_geo {
>> u32 ws_opt; /* optimal write size */
>> u32 mw_cunits; /* distance required for successful read */
>> - /* device capabilities */
>> - u32 mccap;
>> + /* device capabilities. Note that this represents capabilities in 1.2
>> + * and media and controller capabilities in 2.0
>> + */
>> + u32 cap;
>
> Here is a list of capabilities:
>
> 1.2
> Bad block mgmt
> Hybrid command support
>
> 2.0
>
> Vector copy
> Double reset
>
> The way I was thinking it would be implemented is to split the upper cap bits to 2.0, and let the lower bits be reserved for 1.2.
>
> Such that one would define the following:
>
> enum {
> NVM_CAP_BBM 1 << 0;
> NVM_CAP_HCS 1 << 1;
>
> NVM_CAP_VCPY 1 << 16;
> NVM_CAP_DRST 1 << 17;
> };
>
> That way, the assignment from 2.0 can easily be done with cap = le32_to_cpu(id->mccap) << 16;
>
> and targets and other don't need to understand the difference between 1.2 and 2.0 format.

I can see that you already have a way to do it in mind. I'll remove this
patch and you can implement it later on.

Javier


Attachments:
signature.asc (849.00 B)
Message signed with OpenPGP