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 <javier@cnexlabs.com>
Signed-off-by: Matias Bjørling <mb@lightnvm.io>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index e55b105..6e65056 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_addrf_12 {
 	u8	ch_len;
-	u8	lun_offset;
 	u8	lun_len;
-	u8	pln_offset;
-	u8	pln_len;
-	u8	blk_offset;
 	u8	blk_len;
-	u8	pg_offset;
 	u8	pg_len;
-	u8	sect_offset;
+	u8	pln_len;
 	u8	sect_len;
+
+	u8	ch_offset;
+	u8	lun_offset;
+	u8	blk_offset;
+	u8	pg_offset;
+	u8	pln_offset;
+	u8	sect_offset;
+
+	u64	ch_mask;
+	u64	lun_mask;
+	u64	blk_mask;
+	u64	pg_mask;
+	u64	pln_mask;
+	u64	sec_mask;
 };
 
-struct nvm_id {
-	u8	ver_id;
-	u8	vmnt;
-	u32	cap;
-	u32	dom;
+struct nvm_addrf {
+	u8	ch_len;
+	u8	lun_len;
+	u8	chk_len;
+	u8	sec_len;
+	u8	rsv_len[2];
 
-	struct	nvm_addr_format ppaf;
+	u8	ch_offset;
+	u8	lun_offset;
+	u8	chk_offset;
+	u8	sec_offset;
+	u8	rsv_off[2];
 
-	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;
-
-	u8	num_pln;
-	u16	num_pg;
-	u16	fpg_sz;
-} __packed;
+	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_addrf 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,15 @@ 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_addrf_12 *ppaf = (struct nvm_addrf_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 +380,17 @@ 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_addrf_12 *ppaf = (struct nvm_addrf_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;
 }