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>
This commit is contained in:
Javier González 2018-03-30 00:05:10 +02:00 committed by Jens Axboe
parent 43d4712721
commit e46f4e4822
12 changed files with 452 additions and 426 deletions

View file

@ -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;
}