diff mbox

[20/20] lightnvm: pblk: implement 2.0 support

Message ID 1519205218-26994-21-git-send-email-javier@cnexlabs.com (mailing list archive)
State New, archived
Headers show

Commit Message

=?UTF-8?q?Javier=20Gonz=C3=A1lez?= Feb. 21, 2018, 9:26 a.m. UTC
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@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(-)

Comments

=?UTF-8?q?Javier=20Gonz=C3=A1lez?= Feb. 21, 2018, 2:30 p.m. UTC | #1
BTW, there is a V3 for this patch at least, adding holes in the mapping
bitmap to avoid the multiplications and divisions on the fast path, when
the media format is not a power of two. I'll send it this week; just
wanted to get this out for revision.

Javier

> On 21 Feb 2018, at 10.26, Javier González <jg@lightnvm.io> 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@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 c5c304a37554..ce9aa4b3b09a 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->c.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->c.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->c.clba, pblk->min_write_pgs, &mod);
> -	if (mod) {
> -		pr_err("pblk: bad configuration of sectors/pages\n");
> +	switch (geo->c.version) {
> +	case NVM_OCSSD_SPEC_12:
> +		div_u64_rem(geo->c.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->c.version);
> 		return -EINVAL;
> 	}
> 
> -	pblk->addrf_len = pblk_set_addrf_12(geo, (void *)&pblk->addrf);
> -
> 	return 0;
> }
> 
> @@ -1110,7 +1153,9 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
> 	struct pblk *pblk;
> 	int ret;
> 
> -	if (geo->c.version != NVM_OCSSD_SPEC_12) {
> +	/* pblk supports 1.2 and 2.0 versions */
> +	if (!(geo->c.version == NVM_OCSSD_SPEC_12 ||
> +					geo->c.version == NVM_OCSSD_SPEC_20)) {
> 		pr_err("pblk: OCSSD version not supported (%u)\n",
> 							geo->c.version);
> 		return ERR_PTR(-EINVAL);
> diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
> index 191af0c6591e..60b8d931e4ba 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->c.addrf;
> +	if (geo->c.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->c.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->c.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 c66fa0c28adf..b92a1145ad97 100644
> --- a/drivers/lightnvm/pblk.h
> +++ b/drivers/lightnvm/pblk.h
> @@ -574,6 +574,18 @@ enum {
> 	PBLK_STATE_STOPPED = 3,
> };
> 
> +/* Internal format to support not power-of-2 device formats (for now) */
> +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;
> @@ -586,7 +598,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;
> @@ -967,17 +980,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->c.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.ch = chnls;
> +
> +		sector_div(paddr, uaddrf->ch_stripe);
> +		div_u64_rem(paddr, uaddrf->lun_stripe, &luns);
> +		ppa.m.lun = luns;
> +
> +		sector_div(paddr, uaddrf->lun_stripe);
> +		ppa.m.sec += uaddrf->sec_stripe * paddr;
> +	}
> 
> 	return ppa;
> }
> @@ -985,15 +1024,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->c.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.ch * uaddrf->sec_stripe;
> +		paddr += (u64)p.m.lun * 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;
> }
> @@ -1010,15 +1066,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->c.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.ch = (ppa32 & lbaf->ch_mask) >>
> +							lbaf->ch_offset;
> +			ppa64.m.lun = (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;
> @@ -1034,15 +1112,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->c.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.ch << lbaf->ch_offset;
> +			ppa32 |= ppa64.m.lun << lbaf->lun_offset;
> +			ppa32 |= ppa64.m.chk << lbaf->chk_offset;
> +			ppa32 |= ppa64.m.sec << lbaf->sec_offset;
> +		}
> 	}
> 
> 	return ppa32;
> @@ -1160,6 +1250,9 @@ static inline int pblk_set_progr_mode(struct pblk *pblk, int type)
> 	struct nvm_geo *geo = &dev->geo;
> 	int flags;
> 
> +	if (geo->c.version == NVM_OCSSD_SPEC_20)
> +		return 0;
> +
> 	flags = geo->c.pln_mode >> 1;
> 
> 	if (type == PBLK_WRITE)
> @@ -1179,6 +1272,9 @@ static inline int pblk_set_read_mode(struct pblk *pblk, int type)
> 	struct nvm_geo *geo = &dev->geo;
> 	int flags;
> 
> +	if (geo->c.version == NVM_OCSSD_SPEC_20)
> +		return 0;
> +
> 	flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
> 	if (type == PBLK_READ_SEQUENTIAL)
> 		flags |= geo->c.pln_mode >> 1;
> @@ -1192,16 +1288,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->c.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.ch, p->m.lun, p->m.chk, p->m.sec);
> 	}
> }
> 
> @@ -1211,13 +1312,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);
> @@ -1233,16 +1334,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->c.num_pln &&
> -				ppa->g.blk < geo->c.num_chk &&
> -				ppa->g.pg < geo->c.num_pg &&
> -				ppa->g.sec < geo->c.ws_min)
> -			continue;
> +		if (geo->c.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->c.num_pln &&
> +					ppa->g.blk < geo->c.num_chk &&
> +					ppa->g.pg < geo->c.num_pg &&
> +					ppa->g.sec < geo->c.ws_min)
> +				continue;
> +		} else {
> +			if (!ppa->c.is_cached &&
> +					ppa->m.ch < geo->num_ch &&
> +					ppa->m.lun < geo->num_lun &&
> +					ppa->m.chk < geo->c.num_chk &&
> +					ppa->m.sec < geo->c.clba)
> +				continue;
> +		}
> 
> -		print_ppa(ppa, "boundary", i);
> +		print_ppa(geo, ppa, "boundary", i);
> 
> 		return 1;
> 	}
> --
> 2.7.4
> 
> 
> _______________________________________________
> Linux-nvme mailing list
> Linux-nvme@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-nvme
diff mbox

Patch

diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index c5c304a37554..ce9aa4b3b09a 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->c.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->c.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->c.clba, pblk->min_write_pgs, &mod);
-	if (mod) {
-		pr_err("pblk: bad configuration of sectors/pages\n");
+	switch (geo->c.version) {
+	case NVM_OCSSD_SPEC_12:
+		div_u64_rem(geo->c.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->c.version);
 		return -EINVAL;
 	}
 
-	pblk->addrf_len = pblk_set_addrf_12(geo, (void *)&pblk->addrf);
-
 	return 0;
 }
 
@@ -1110,7 +1153,9 @@  static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
 	struct pblk *pblk;
 	int ret;
 
-	if (geo->c.version != NVM_OCSSD_SPEC_12) {
+	/* pblk supports 1.2 and 2.0 versions */
+	if (!(geo->c.version == NVM_OCSSD_SPEC_12 ||
+					geo->c.version == NVM_OCSSD_SPEC_20)) {
 		pr_err("pblk: OCSSD version not supported (%u)\n",
 							geo->c.version);
 		return ERR_PTR(-EINVAL);
diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
index 191af0c6591e..60b8d931e4ba 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->c.addrf;
+	if (geo->c.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->c.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->c.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 c66fa0c28adf..b92a1145ad97 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -574,6 +574,18 @@  enum {
 	PBLK_STATE_STOPPED = 3,
 };
 
+/* Internal format to support not power-of-2 device formats (for now) */
+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;
@@ -586,7 +598,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;
@@ -967,17 +980,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->c.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.ch = chnls;
+
+		sector_div(paddr, uaddrf->ch_stripe);
+		div_u64_rem(paddr, uaddrf->lun_stripe, &luns);
+		ppa.m.lun = luns;
+
+		sector_div(paddr, uaddrf->lun_stripe);
+		ppa.m.sec += uaddrf->sec_stripe * paddr;
+	}
 
 	return ppa;
 }
@@ -985,15 +1024,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->c.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.ch * uaddrf->sec_stripe;
+		paddr += (u64)p.m.lun * 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;
 }
@@ -1010,15 +1066,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->c.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.ch = (ppa32 & lbaf->ch_mask) >>
+							lbaf->ch_offset;
+			ppa64.m.lun = (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;
@@ -1034,15 +1112,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->c.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.ch << lbaf->ch_offset;
+			ppa32 |= ppa64.m.lun << lbaf->lun_offset;
+			ppa32 |= ppa64.m.chk << lbaf->chk_offset;
+			ppa32 |= ppa64.m.sec << lbaf->sec_offset;
+		}
 	}
 
 	return ppa32;
@@ -1160,6 +1250,9 @@  static inline int pblk_set_progr_mode(struct pblk *pblk, int type)
 	struct nvm_geo *geo = &dev->geo;
 	int flags;
 
+	if (geo->c.version == NVM_OCSSD_SPEC_20)
+		return 0;
+
 	flags = geo->c.pln_mode >> 1;
 
 	if (type == PBLK_WRITE)
@@ -1179,6 +1272,9 @@  static inline int pblk_set_read_mode(struct pblk *pblk, int type)
 	struct nvm_geo *geo = &dev->geo;
 	int flags;
 
+	if (geo->c.version == NVM_OCSSD_SPEC_20)
+		return 0;
+
 	flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
 	if (type == PBLK_READ_SEQUENTIAL)
 		flags |= geo->c.pln_mode >> 1;
@@ -1192,16 +1288,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->c.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.ch, p->m.lun, p->m.chk, p->m.sec);
 	}
 }
 
@@ -1211,13 +1312,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);
@@ -1233,16 +1334,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->c.num_pln &&
-				ppa->g.blk < geo->c.num_chk &&
-				ppa->g.pg < geo->c.num_pg &&
-				ppa->g.sec < geo->c.ws_min)
-			continue;
+		if (geo->c.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->c.num_pln &&
+					ppa->g.blk < geo->c.num_chk &&
+					ppa->g.pg < geo->c.num_pg &&
+					ppa->g.sec < geo->c.ws_min)
+				continue;
+		} else {
+			if (!ppa->c.is_cached &&
+					ppa->m.ch < geo->num_ch &&
+					ppa->m.lun < geo->num_lun &&
+					ppa->m.chk < geo->c.num_chk &&
+					ppa->m.sec < geo->c.clba)
+				continue;
+		}
 
-		print_ppa(ppa, "boundary", i);
+		print_ppa(geo, ppa, "boundary", i);
 
 		return 1;
 	}