]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - include/linux/lightnvm.h
lightnvm: use target nvm on target-specific ops.
[linux.git] / include / linux / lightnvm.h
index d190786e4ad81262ddf8161359e2ab1e093349b2..e76f9c4aa49b26a73117d423be16271c191a1359 100644 (file)
@@ -47,6 +47,7 @@ struct ppa_addr {
 struct nvm_rq;
 struct nvm_id;
 struct nvm_dev;
+struct nvm_tgt_dev;
 
 typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
 typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
@@ -107,6 +108,8 @@ enum {
        NVM_RSP_NOT_CHANGEABLE  = 0x1,
        NVM_RSP_ERR_FAILWRITE   = 0x40ff,
        NVM_RSP_ERR_EMPTYPAGE   = 0x42ff,
+       NVM_RSP_ERR_FAILECC     = 0x4281,
+       NVM_RSP_WARN_HIGHECC    = 0x4700,
 
        /* Device opcodes */
        NVM_OP_HBREAD           = 0x02,
@@ -208,7 +211,7 @@ struct nvm_id {
 
 struct nvm_target {
        struct list_head list;
-       struct nvm_dev *dev;
+       struct nvm_tgt_dev *dev;
        struct nvm_tgt_type *type;
        struct gendisk *disk;
 };
@@ -228,7 +231,7 @@ typedef void (nvm_end_io_fn)(struct nvm_rq *);
 
 struct nvm_rq {
        struct nvm_tgt_instance *ins;
-       struct nvm_dev *dev;
+       struct nvm_tgt_dev *dev;
 
        struct bio *bio;
 
@@ -263,35 +266,12 @@ static inline void *nvm_rq_to_pdu(struct nvm_rq *rqdata)
        return rqdata + 1;
 }
 
-struct nvm_block;
-
-struct nvm_lun {
-       int id;
-
-       int lun_id;
-       int chnl_id;
-
-       spinlock_t lock;
-
-       unsigned int nr_free_blocks;    /* Number of unused blocks */
-       struct nvm_block *blocks;
-};
-
 enum {
        NVM_BLK_ST_FREE =       0x1,    /* Free block */
        NVM_BLK_ST_TGT =        0x2,    /* Block in use by target */
        NVM_BLK_ST_BAD =        0x8,    /* Bad block */
 };
 
-struct nvm_block {
-       struct list_head list;
-       struct nvm_lun *lun;
-       unsigned long id;
-
-       void *priv;
-       int state;
-};
-
 /* system block cpu representation */
 struct nvm_sb_info {
        unsigned long           seqnr;
@@ -301,22 +281,12 @@ struct nvm_sb_info {
        struct ppa_addr         fs_ppa;
 };
 
-struct nvm_dev {
-       struct nvm_dev_ops *ops;
-
-       struct list_head devices;
-
-       /* Media manager */
-       struct nvmm_type *mt;
-       void *mp;
-
-       /* System blocks */
-       struct nvm_sb_info sb;
-
-       /* Device information */
+/* Device generic information */
+struct nvm_geo {
        int nr_chnls;
+       int nr_luns;
+       int luns_per_chnl; /* -1 if channels are not symmetric */
        int nr_planes;
-       int luns_per_chnl;
        int sec_per_pg; /* only sectors for a single page */
        int pgs_per_blk;
        int blks_per_lun;
@@ -336,14 +306,44 @@ struct nvm_dev {
        int sec_per_pl; /* all sectors across planes */
        int sec_per_blk;
        int sec_per_lun;
+};
+
+struct nvm_tgt_dev {
+       /* Device information */
+       struct nvm_geo geo;
+
+       /* 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;
+       void *map;
+};
+
+struct nvm_dev {
+       struct nvm_dev_ops *ops;
+
+       struct list_head devices;
+
+       /* Media manager */
+       struct nvmm_type *mt;
+       void *mp;
+
+       /* System blocks */
+       struct nvm_sb_info sb;
+
+       /* Device information */
+       struct nvm_geo geo;
 
        /* lower page table */
        int lps_per_blk;
        int *lptbl;
 
-       unsigned long total_blocks;
        unsigned long total_secs;
-       int nr_luns;
 
        unsigned long *lun_map;
        void *dma_pool;
@@ -352,26 +352,57 @@ struct nvm_dev {
 
        /* Backend device */
        struct request_queue *q;
-       struct device dev;
-       struct device *parent_dev;
        char name[DISK_NAME_LEN];
        void *private_data;
 
+       void *rmap;
+
        struct mutex mlock;
        spinlock_t lock;
 };
 
+static inline struct ppa_addr linear_to_generic_addr(struct nvm_geo *geo,
+                                                    u64 pba)
+{
+       struct ppa_addr l;
+       int secs, pgs, blks, luns;
+       sector_t ppa = pba;
+
+       l.ppa = 0;
+
+       div_u64_rem(ppa, geo->sec_per_pg, &secs);
+       l.g.sec = secs;
+
+       sector_div(ppa, geo->sec_per_pg);
+       div_u64_rem(ppa, geo->pgs_per_blk, &pgs);
+       l.g.pg = pgs;
+
+       sector_div(ppa, geo->pgs_per_blk);
+       div_u64_rem(ppa, geo->blks_per_lun, &blks);
+       l.g.blk = blks;
+
+       sector_div(ppa, geo->blks_per_lun);
+       div_u64_rem(ppa, geo->luns_per_chnl, &luns);
+       l.g.lun = luns;
+
+       sector_div(ppa, geo->luns_per_chnl);
+       l.g.ch = ppa;
+
+       return l;
+}
+
 static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
                                                struct ppa_addr r)
 {
+       struct nvm_geo *geo = &dev->geo;
        struct ppa_addr l;
 
-       l.ppa = ((u64)r.g.blk) << dev->ppaf.blk_offset;
-       l.ppa |= ((u64)r.g.pg) << dev->ppaf.pg_offset;
-       l.ppa |= ((u64)r.g.sec) << dev->ppaf.sect_offset;
-       l.ppa |= ((u64)r.g.pl) << dev->ppaf.pln_offset;
-       l.ppa |= ((u64)r.g.lun) << dev->ppaf.lun_offset;
-       l.ppa |= ((u64)r.g.ch) << dev->ppaf.ch_offset;
+       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;
 
        return l;
 }
@@ -379,24 +410,25 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
 static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev,
                                                struct ppa_addr r)
 {
+       struct nvm_geo *geo = &dev->geo;
        struct ppa_addr l;
 
        l.ppa = 0;
        /*
         * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc.
         */
-       l.g.blk = (r.ppa >> dev->ppaf.blk_offset) &
-                                       (((1 << dev->ppaf.blk_len) - 1));
-       l.g.pg |= (r.ppa >> dev->ppaf.pg_offset) &
-                                       (((1 << dev->ppaf.pg_len) - 1));
-       l.g.sec |= (r.ppa >> dev->ppaf.sect_offset) &
-                                       (((1 << dev->ppaf.sect_len) - 1));
-       l.g.pl |= (r.ppa >> dev->ppaf.pln_offset) &
-                                       (((1 << dev->ppaf.pln_len) - 1));
-       l.g.lun |= (r.ppa >> dev->ppaf.lun_offset) &
-                                       (((1 << dev->ppaf.lun_len) - 1));
-       l.g.ch |= (r.ppa >> dev->ppaf.ch_offset) &
-                                       (((1 << dev->ppaf.ch_len) - 1));
+       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));
 
        return l;
 }
@@ -411,18 +443,13 @@ static inline void ppa_set_empty(struct ppa_addr *ppa_addr)
        ppa_addr->ppa = ADDR_EMPTY;
 }
 
-static inline struct ppa_addr block_to_ppa(struct nvm_dev *dev,
-                                                       struct nvm_block *blk)
+static inline int ppa_cmp_blk(struct ppa_addr ppa1, struct ppa_addr ppa2)
 {
-       struct ppa_addr ppa;
-       struct nvm_lun *lun = blk->lun;
-
-       ppa.ppa = 0;
-       ppa.g.blk = blk->id % dev->blks_per_lun;
-       ppa.g.lun = lun->lun_id;
-       ppa.g.ch = lun->chnl_id;
+       if (ppa_empty(ppa1) || ppa_empty(ppa2))
+               return 0;
 
-       return ppa;
+       return ((ppa1.g.ch == ppa2.g.ch) && (ppa1.g.lun == ppa2.g.lun) &&
+                                       (ppa1.g.blk == ppa2.g.blk));
 }
 
 static inline int ppa_to_slc(struct nvm_dev *dev, int slc_pg)
@@ -432,7 +459,7 @@ static inline int ppa_to_slc(struct nvm_dev *dev, int slc_pg)
 
 typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
 typedef sector_t (nvm_tgt_capacity_fn)(void *);
-typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *, int, int);
+typedef void *(nvm_tgt_init_fn)(struct nvm_tgt_dev *, struct gendisk *);
 typedef void (nvm_tgt_exit_fn)(void *);
 
 struct nvm_tgt_type {
@@ -465,23 +492,11 @@ typedef void (nvmm_unregister_fn)(struct nvm_dev *);
 
 typedef int (nvmm_create_tgt_fn)(struct nvm_dev *, struct nvm_ioctl_create *);
 typedef int (nvmm_remove_tgt_fn)(struct nvm_dev *, struct nvm_ioctl_remove *);
-typedef struct nvm_block *(nvmm_get_blk_fn)(struct nvm_dev *,
-                                             struct nvm_lun *, unsigned long);
-typedef void (nvmm_put_blk_fn)(struct nvm_dev *, struct nvm_block *);
-typedef int (nvmm_open_blk_fn)(struct nvm_dev *, struct nvm_block *);
-typedef int (nvmm_close_blk_fn)(struct nvm_dev *, struct nvm_block *);
-typedef void (nvmm_flush_blk_fn)(struct nvm_dev *, struct nvm_block *);
-typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
-typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
-                                                               unsigned long);
-typedef void (nvmm_mark_blk_fn)(struct nvm_dev *, struct ppa_addr, int);
-typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
-typedef int (nvmm_reserve_lun)(struct nvm_dev *, int);
-typedef void (nvmm_release_lun)(struct nvm_dev *, int);
-typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
-
+typedef int (nvmm_submit_io_fn)(struct nvm_tgt_dev *, struct nvm_rq *);
+typedef int (nvmm_erase_blk_fn)(struct nvm_tgt_dev *, struct ppa_addr *, int);
 typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
 typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t);
+typedef void (nvmm_part_to_tgt_fn)(struct nvm_dev *, sector_t*, int);
 
 struct nvmm_type {
        const char *name;
@@ -493,54 +508,40 @@ struct nvmm_type {
        nvmm_create_tgt_fn *create_tgt;
        nvmm_remove_tgt_fn *remove_tgt;
 
-       /* Block administration callbacks */
-       nvmm_get_blk_fn *get_blk;
-       nvmm_put_blk_fn *put_blk;
-       nvmm_open_blk_fn *open_blk;
-       nvmm_close_blk_fn *close_blk;
-       nvmm_flush_blk_fn *flush_blk;
-
        nvmm_submit_io_fn *submit_io;
        nvmm_erase_blk_fn *erase_blk;
 
-       /* Bad block mgmt */
-       nvmm_mark_blk_fn *mark_blk;
-
-       /* Configuration management */
-       nvmm_get_lun_fn *get_lun;
-       nvmm_reserve_lun *reserve_lun;
-       nvmm_release_lun *release_lun;
-
-       /* Statistics */
-       nvmm_lun_info_print_fn *lun_info_print;
-
        nvmm_get_area_fn *get_area;
        nvmm_put_area_fn *put_area;
 
+       nvmm_part_to_tgt_fn *part_to_tgt;
+
        struct list_head list;
 };
 
 extern int nvm_register_mgr(struct nvmm_type *);
 extern void nvm_unregister_mgr(struct nvmm_type *);
 
-extern struct nvm_block *nvm_get_blk(struct nvm_dev *, struct nvm_lun *,
-                                                               unsigned long);
-extern void nvm_put_blk(struct nvm_dev *, struct nvm_block *);
-
 extern struct nvm_dev *nvm_alloc_dev(int);
 extern int nvm_register(struct nvm_dev *);
 extern void nvm_unregister(struct nvm_dev *);
 
-void nvm_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type);
+extern int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas,
+                                                       int nr_ppas, int type);
 
-extern int nvm_submit_io(struct nvm_dev *, struct nvm_rq *);
+extern int nvm_max_phys_sects(struct nvm_tgt_dev *);
+extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *);
 extern void nvm_generic_to_addr_mode(struct nvm_dev *, struct nvm_rq *);
 extern void nvm_addr_to_generic_mode(struct nvm_dev *, struct nvm_rq *);
 extern int nvm_set_rqd_ppalist(struct nvm_dev *, struct nvm_rq *,
                                        const struct ppa_addr *, int, int);
 extern void nvm_free_rqd_ppalist(struct nvm_dev *, struct nvm_rq *);
-extern int nvm_erase_ppa(struct nvm_dev *, struct ppa_addr *, int);
-extern int nvm_erase_blk(struct nvm_dev *, struct nvm_block *);
+extern int nvm_erase_ppa(struct nvm_dev *, struct ppa_addr *, int, int);
+extern int nvm_erase_blk(struct nvm_tgt_dev *, struct ppa_addr *, int);
+extern int nvm_get_l2p_tbl(struct nvm_tgt_dev *, u64, u32, nvm_l2p_update_fn *,
+                          void *);
+extern int nvm_get_area(struct nvm_tgt_dev *, sector_t *, sector_t);
+extern void nvm_put_area(struct nvm_tgt_dev *, sector_t);
 extern void nvm_end_io(struct nvm_rq *, int);
 extern int nvm_submit_ppa(struct nvm_dev *, struct ppa_addr *, int, int, int,
                                                                void *, int);
@@ -569,10 +570,10 @@ extern int nvm_init_sysblock(struct nvm_dev *, struct nvm_sb_info *);
 
 extern int nvm_dev_factory(struct nvm_dev *, int flags);
 
-#define nvm_for_each_lun_ppa(dev, ppa, chid, lunid)                    \
-       for ((chid) = 0, (ppa).ppa = 0; (chid) < (dev)->nr_chnls;       \
+#define nvm_for_each_lun_ppa(geo, ppa, chid, lunid)                    \
+       for ((chid) = 0, (ppa).ppa = 0; (chid) < (geo)->nr_chnls;       \
                                        (chid)++, (ppa).g.ch = (chid))  \
-               for ((lunid) = 0; (lunid) < (dev)->luns_per_chnl;       \
+               for ((lunid) = 0; (lunid) < (geo)->luns_per_chnl;       \
                                        (lunid)++, (ppa).g.lun = (lunid))
 
 #else /* CONFIG_NVM */