[PATCH 15/15] lightnvm: pblk: implement 2.0 support
Matias Bjørling
mb at lightnvm.io
Thu Mar 1 02:48:54 PST 2018
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 <javier at cnexlabs.com>
> ---
> 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.
More information about the Linux-nvme
mailing list