Hi Jens,
This is the patches targeted for -rc2 of 4.4.
Ten of the patches fix bugs and small specification updates. While the
last two are larger patches. They are necessary because of specification
changes. The updates are applied now before it is set in stone for 4.4
(or at least makes it a lot harder to change)
Patch 1: Adds the linux-block list to the maintainers list for LightNVM.
Patch 2: Fixes a ushort bug reported by Geert.
Patch 3: Updates the implementation to support the new bad block table
format.
Patch 4-9: Small fixes.
Patch 10: The specification had support for both linear and device
specific addressing. It was replaced by ppa format, that
defines the device ppa format used by the specific device.
This patch adds the support and removes the previous two
modes.
Patch 11-12: Two small cleanups to the lightnvm nvme integration.
Caused by specification changes.
Patches 3 to 12 is the first time they are posted to the list for
review.
Will you pick up the patches when convenient (and reviewed):
[email protected]:OpenChannelSSD/linux.git for-jens
I'll update the for-jens branch and post a separate patch if any
fixes is applied to the patches.
Javier González (1):
lightnvm: cleanup queue before target removal
Matias Bjørling (12):
MAINTAINERS: Add linux-block list to LightNVM for patches
lightnvm: change max_phys_sect to uint
lightnvm: update bad block table format
lightnvm: update alignments for identify command
lightnvm: expose mccap in identify command
lightnvm: remove unused attrs in nvm_id structs
lightnvm: check for NAND flash and its type
lightnvm: prematurely activate nvm_dev
lightnvm: prevent double free on init error
lightnvm: remove linear and device addr modes
nvme: missing ppaf copy
nvme: remove reserved double word
MAINTAINERS | 1 +
drivers/lightnvm/core.c | 37 +++++-----
drivers/lightnvm/gennvm.c | 40 ++++++----
drivers/lightnvm/gennvm.h | 2 +
drivers/lightnvm/rrpc.c | 32 +++++++-
drivers/nvme/host/lightnvm.c | 126 +++++++++++++++++++++++++-------
include/linux/lightnvm.h | 170 ++++++++++---------------------------------
7 files changed, 219 insertions(+), 189 deletions(-)
--
2.1.4
Signed-off-by: Matias Bjørling <[email protected]>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index f56a10a..2c4ec7a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6337,6 +6337,7 @@ F: arch/*/include/asm/pmem.h
LIGHTNVM PLATFORM SUPPORT
M: Matias Bjorling <[email protected]>
W: http://github/OpenChannelSSD
+L: [email protected]
S: Maintained
F: drivers/lightnvm/
F: include/linux/lightnvm.h
--
2.1.4
The max_phys_sect variable is defined as a char. We do a boundary check
to maximally allow 256 physical page descriptors per command. As we are
not indexing from zero. This expression is always false. Bump the
max_phys_sect to an unsigned int to support the range check.
Signed-off-by: Matias Bjørling <[email protected]>
Reported-by: Geert Uytterhoeven <[email protected]>
---
include/linux/lightnvm.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 69c9057..32b5369 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -220,7 +220,7 @@ struct nvm_dev_ops {
nvm_dev_dma_alloc_fn *dev_dma_alloc;
nvm_dev_dma_free_fn *dev_dma_free;
- uint8_t max_phys_sect;
+ unsigned int max_phys_sect;
};
struct nvm_lun {
--
2.1.4
The specification was changed to reflect a multi-value bad block table.
Instead of bit-based bad block table, the bad block table now allows
eight bad block categories. Currently four are defined:
* Factory bad blocks
* Grown bad blocks
* Device-side reserved blocks
* Host-side reserved blocks
The factory and grown bad blocks are the regular bad blocks. The
reserved blocks are either for internal use or external use. In
particular, the device-side reserved blocks allows the host to
bootstrap from a limited number of flash blocks. Reducing the flash
blocks to scan upon super block initialization.
Support for both get bad block table and set bad block table is added.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/lightnvm/gennvm.c | 32 ++++++++----
drivers/lightnvm/gennvm.h | 2 +
drivers/nvme/host/lightnvm.c | 113 ++++++++++++++++++++++++++++++++++---------
include/linux/lightnvm.h | 6 +--
4 files changed, 117 insertions(+), 36 deletions(-)
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index ae1fb2b..8cfc011 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -64,19 +64,22 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn)
return 0;
}
-static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks,
+static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks,
void *private)
{
struct gen_nvm *gn = private;
- struct gen_lun *lun = &gn->luns[lun_id];
+ struct nvm_dev *dev = gn->dev;
+ struct gen_lun *lun;
struct nvm_block *blk;
int i;
- if (unlikely(bitmap_empty(bb_bitmap, nr_blocks)))
- return 0;
+ ppa = addr_to_generic_mode(gn->dev, ppa);
+ lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun];
+
+ for (i = 0; i < nr_blocks; i++) {
+ if (blks[i] == 0)
+ continue;
- i = -1;
- while ((i = find_next_bit(bb_bitmap, nr_blocks, i + 1)) < nr_blocks) {
blk = &lun->vlun.blocks[i];
if (!blk) {
pr_err("gennvm: BB data is out of bounds.\n");
@@ -171,8 +174,16 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
}
if (dev->ops->get_bb_tbl) {
- ret = dev->ops->get_bb_tbl(dev->q, lun->vlun.id,
- dev->blks_per_lun, gennvm_block_bb, gn);
+ struct ppa_addr ppa;
+
+ ppa.ppa = 0;
+ ppa.g.ch = lun->vlun.chnl_id;
+ ppa.g.lun = lun->vlun.id;
+ ppa = generic_to_addr_mode(dev, ppa);
+
+ ret = dev->ops->get_bb_tbl(dev->q, ppa,
+ dev->blks_per_lun,
+ gennvm_block_bb, gn);
if (ret)
pr_err("gennvm: could not read BB table\n");
}
@@ -199,6 +210,7 @@ static int gennvm_register(struct nvm_dev *dev)
if (!gn)
return -ENOMEM;
+ gn->dev = dev;
gn->nr_luns = dev->nr_luns;
dev->mp = gn;
@@ -354,10 +366,10 @@ static void gennvm_mark_blk_bad(struct nvm_dev *dev, struct nvm_rq *rqd)
{
int i;
- if (!dev->ops->set_bb)
+ if (!dev->ops->set_bb_tbl)
return;
- if (dev->ops->set_bb(dev->q, rqd, 1))
+ if (dev->ops->set_bb_tbl(dev->q, rqd, 1))
return;
gennvm_addr_to_generic_mode(dev, rqd);
diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h
index d23bd35..9c24b5b 100644
--- a/drivers/lightnvm/gennvm.h
+++ b/drivers/lightnvm/gennvm.h
@@ -35,6 +35,8 @@ struct gen_lun {
};
struct gen_nvm {
+ struct nvm_dev *dev;
+
int nr_luns;
struct gen_lun *luns;
};
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index e0b7b95..2c35465 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -93,7 +93,7 @@ struct nvme_nvm_l2ptbl {
__le16 cdw14[6];
};
-struct nvme_nvm_bbtbl {
+struct nvme_nvm_getbbtbl {
__u8 opcode;
__u8 flags;
__u16 command_id;
@@ -101,10 +101,23 @@ struct nvme_nvm_bbtbl {
__u64 rsvd[2];
__le64 prp1;
__le64 prp2;
- __le32 prp1_len;
- __le32 prp2_len;
- __le32 lbb;
- __u32 rsvd11[3];
+ __le64 spba;
+ __u32 rsvd4[4];
+};
+
+struct nvme_nvm_setbbtbl {
+ __u8 opcode;
+ __u8 flags;
+ __u16 command_id;
+ __le32 nsid;
+ __le64 rsvd[2];
+ __le64 prp1;
+ __le64 prp2;
+ __le64 spba;
+ __le16 nlb;
+ __u8 value;
+ __u8 rsvd3;
+ __u32 rsvd4[3];
};
struct nvme_nvm_erase_blk {
@@ -129,8 +142,8 @@ struct nvme_nvm_command {
struct nvme_nvm_hb_rw hb_rw;
struct nvme_nvm_ph_rw ph_rw;
struct nvme_nvm_l2ptbl l2p;
- struct nvme_nvm_bbtbl get_bb;
- struct nvme_nvm_bbtbl set_bb;
+ struct nvme_nvm_getbbtbl get_bb;
+ struct nvme_nvm_setbbtbl set_bb;
struct nvme_nvm_erase_blk erase;
};
};
@@ -187,6 +200,20 @@ struct nvme_nvm_id {
struct nvme_nvm_id_group groups[4];
} __packed;
+struct nvme_nvm_bb_tbl {
+ __u8 tblid[4];
+ __le16 verid;
+ __le16 revid;
+ __le32 rvsd1;
+ __le32 tblks;
+ __le32 tfact;
+ __le32 tgrown;
+ __le32 tdresv;
+ __le32 thresv;
+ __le32 rsvd2[8];
+ __u8 blk[0];
+};
+
/*
* Check we didn't inadvertently grow the command struct
*/
@@ -195,12 +222,14 @@ static inline void _nvme_nvm_check_size(void)
BUILD_BUG_ON(sizeof(struct nvme_nvm_identity) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_hb_rw) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_ph_rw) != 64);
- BUILD_BUG_ON(sizeof(struct nvme_nvm_bbtbl) != 64);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_getbbtbl) != 64);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_setbbtbl) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_l2ptbl) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_erase_blk) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_id_group) != 960);
BUILD_BUG_ON(sizeof(struct nvme_nvm_addr_format) != 128);
BUILD_BUG_ON(sizeof(struct nvme_nvm_id) != 4096);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 512);
}
static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
@@ -322,43 +351,80 @@ out:
return ret;
}
-static int nvme_nvm_get_bb_tbl(struct request_queue *q, int lunid,
- unsigned int nr_blocks,
- nvm_bb_update_fn *update_bbtbl, void *priv)
+static int nvme_nvm_get_bb_tbl(struct request_queue *q, struct ppa_addr ppa,
+ int nr_blocks, nvm_bb_update_fn *update_bbtbl,
+ void *priv)
{
struct nvme_ns *ns = q->queuedata;
struct nvme_dev *dev = ns->dev;
struct nvme_nvm_command c = {};
- void *bb_bitmap;
- u16 bb_bitmap_size;
+ struct nvme_nvm_bb_tbl *bb_tbl;
+ int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blocks;
int ret = 0;
c.get_bb.opcode = nvme_nvm_admin_get_bb_tbl;
c.get_bb.nsid = cpu_to_le32(ns->ns_id);
- c.get_bb.lbb = cpu_to_le32(lunid);
- bb_bitmap_size = ((nr_blocks >> 15) + 1) * PAGE_SIZE;
- bb_bitmap = kmalloc(bb_bitmap_size, GFP_KERNEL);
- if (!bb_bitmap)
+ c.get_bb.spba = cpu_to_le64(ppa.ppa);
+
+ bb_tbl = kzalloc(tblsz, GFP_KERNEL);
+ if (!bb_tbl)
return -ENOMEM;
- bitmap_zero(bb_bitmap, nr_blocks);
-
- ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, bb_bitmap,
- bb_bitmap_size);
+ ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, bb_tbl, tblsz);
if (ret) {
dev_err(dev->dev, "get bad block table failed (%d)\n", ret);
ret = -EIO;
goto out;
}
- ret = update_bbtbl(lunid, bb_bitmap, nr_blocks, priv);
+ if (bb_tbl->tblid[0] != 'B' || bb_tbl->tblid[1] != 'B' ||
+ bb_tbl->tblid[2] != 'L' || bb_tbl->tblid[3] != 'T') {
+ dev_err(dev->dev, "bbt format mismatch\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (le16_to_cpu(bb_tbl->verid) != 1) {
+ ret = -EINVAL;
+ dev_err(dev->dev, "bbt version not supported\n");
+ goto out;
+ }
+
+ if (le32_to_cpu(bb_tbl->tblks) != nr_blocks) {
+ ret = -EINVAL;
+ dev_err(dev->dev, "bbt unsuspected blocks returned (%u!=%u)",
+ le32_to_cpu(bb_tbl->tblks), nr_blocks);
+ goto out;
+ }
+
+ ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv);
if (ret) {
ret = -EINTR;
goto out;
}
out:
- kfree(bb_bitmap);
+ kfree(bb_tbl);
+ return ret;
+}
+
+static int nvme_nvm_set_bb_tbl(struct request_queue *q, struct nvm_rq *rqd,
+ int type)
+{
+ struct nvme_ns *ns = q->queuedata;
+ struct nvme_dev *dev = ns->dev;
+ struct nvme_nvm_command c = {};
+ int ret = 0;
+
+ c.set_bb.opcode = nvme_nvm_admin_set_bb_tbl;
+ c.set_bb.nsid = cpu_to_le32(ns->ns_id);
+ c.set_bb.spba = cpu_to_le64(rqd->ppa_addr.ppa);
+ c.set_bb.nlb = cpu_to_le16(rqd->nr_pages - 1);
+ c.set_bb.value = type;
+
+ ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, NULL, 0);
+ if (ret)
+ dev_err(dev->dev, "set bad block table failed (%d)\n", ret);
return ret;
}
@@ -474,6 +540,7 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
.get_l2p_tbl = nvme_nvm_get_l2p_tbl,
.get_bb_tbl = nvme_nvm_get_bb_tbl,
+ .set_bb_tbl = nvme_nvm_set_bb_tbl,
.submit_io = nvme_nvm_submit_io,
.erase_block = nvme_nvm_erase_block,
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 32b5369..9b3dc1b 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -191,11 +191,11 @@ static inline void *nvm_rq_to_pdu(struct nvm_rq *rqdata)
struct nvm_block;
typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
-typedef int (nvm_bb_update_fn)(u32, void *, unsigned int, void *);
+typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *);
typedef int (nvm_id_fn)(struct request_queue *, struct nvm_id *);
typedef int (nvm_get_l2p_tbl_fn)(struct request_queue *, u64, u32,
nvm_l2p_update_fn *, void *);
-typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, int, unsigned int,
+typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, struct ppa_addr, int,
nvm_bb_update_fn *, void *);
typedef int (nvm_op_set_bb_fn)(struct request_queue *, struct nvm_rq *, int);
typedef int (nvm_submit_io_fn)(struct request_queue *, struct nvm_rq *);
@@ -210,7 +210,7 @@ struct nvm_dev_ops {
nvm_id_fn *identity;
nvm_get_l2p_tbl_fn *get_l2p_tbl;
nvm_op_bb_tbl_fn *get_bb_tbl;
- nvm_op_set_bb_fn *set_bb;
+ nvm_op_set_bb_fn *set_bb_tbl;
nvm_submit_io_fn *submit_io;
nvm_erase_blk_fn *erase_block;
--
2.1.4
A single 8 bit and 16 bit reserve field were inserted in the
specification to align fields appropriately. Reflect this in the
identify group structure.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/nvme/host/lightnvm.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 2c35465..60687ed 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -155,11 +155,13 @@ struct nvme_nvm_id_group {
__u8 num_ch;
__u8 num_lun;
__u8 num_pln;
+ __u8 rsvd1;
__le16 num_blk;
__le16 num_pg;
__le16 fpg_sz;
__le16 csecs;
__le16 sos;
+ __le16 rsvd2;
__le32 trdt;
__le32 trdm;
__le32 tprt;
@@ -168,7 +170,7 @@ struct nvme_nvm_id_group {
__le32 tbem;
__le32 mpos;
__le16 cpar;
- __u8 reserved[913];
+ __u8 reserved[910];
} __packed;
struct nvme_nvm_addr_format {
--
2.1.4
The mccap field is required for I/O command option support. It defines the
following flash access modes:
* SLC mode
* Erase/Program Suspension
* Scramble On/Off
* Encryption
It is slotted in between mpos and cpar, changing the offset for
cpar as well.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/nvme/host/lightnvm.c | 4 +++-
include/linux/lightnvm.h | 1 +
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 60687ed..52b311c 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -169,8 +169,9 @@ struct nvme_nvm_id_group {
__le32 tbet;
__le32 tbem;
__le32 mpos;
+ __le32 mccap;
__le16 cpar;
- __u8 reserved[910];
+ __u8 reserved[906];
} __packed;
struct nvme_nvm_addr_format {
@@ -265,6 +266,7 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
dst->tbet = le32_to_cpu(src->tbet);
dst->tbem = le32_to_cpu(src->tbem);
dst->mpos = le32_to_cpu(src->mpos);
+ dst->mccap = le32_to_cpu(src->mccap);
dst->cpar = le16_to_cpu(src->cpar);
}
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 9b3dc1b..2572856 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -74,6 +74,7 @@ struct nvm_id_group {
u32 tbet;
u32 tbem;
u32 mpos;
+ u32 mccap;
u16 cpar;
u8 res[913];
} __packed;
--
2.1.4
The nvm_id, nvm_id_group and nvm_addr_format data structures contain
reserved attributes. They are unused by media managers and targets.
Remove them.
Signed-off-by: Matias Bjørling <[email protected]>
---
include/linux/lightnvm.h | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 2572856..e6ef8aa 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -58,7 +58,6 @@ enum {
struct nvm_id_group {
u8 mtype;
u8 fmtype;
- u16 res16;
u8 num_ch;
u8 num_lun;
u8 num_pln;
@@ -76,8 +75,7 @@ struct nvm_id_group {
u32 mpos;
u32 mccap;
u16 cpar;
- u8 res[913];
-} __packed;
+};
struct nvm_addr_format {
u8 ch_offset;
@@ -92,19 +90,16 @@ struct nvm_addr_format {
u8 pg_len;
u8 sect_offset;
u8 sect_len;
- u8 res[4];
};
struct nvm_id {
u8 ver_id;
u8 vmnt;
u8 cgrps;
- u8 res[5];
u32 cap;
u32 dom;
struct nvm_addr_format ppaf;
u8 ppat;
- u8 resv[224];
struct nvm_id_group groups[4];
} __packed;
--
2.1.4
Only NAND flash with SLC and MLC is supported. Make sure to not try to
initialize TLC memory or other non-volatile memory types.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/lightnvm/core.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index f659e60..0985a03 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -185,6 +185,16 @@ static int nvm_core_init(struct nvm_dev *dev)
dev->plane_mode = NVM_PLANE_SINGLE;
dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size;
+ if (grp->mtype != 0) {
+ pr_err("nvm: memory type not supported\n");
+ return -EINVAL;
+ }
+
+ if (grp->fmtype != 0 && grp->fmtype != 1) {
+ pr_err("nvm: flash type not supported\n");
+ return -EINVAL;
+ }
+
if (grp->mpos & 0x020202)
dev->plane_mode = NVM_PLANE_DOUBLE;
if (grp->mpos & 0x040404)
--
2.1.4
We register with nvm_devices when there registration can still fail.
Move the final registration at the end of the nvm_register function
to make sure we are fully registered when added to the nvm_devices list.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/lightnvm/core.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 0985a03..40e6cfa 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -318,10 +318,6 @@ int nvm_register(struct request_queue *q, char *disk_name,
if (ret)
goto err_init;
- down_write(&nvm_lock);
- list_add(&dev->devices, &nvm_devices);
- up_write(&nvm_lock);
-
if (dev->ops->max_phys_sect > 1) {
dev->ppalist_pool = dev->ops->create_dma_pool(dev->q,
"ppalist");
@@ -334,6 +330,10 @@ int nvm_register(struct request_queue *q, char *disk_name,
return -EINVAL;
}
+ down_write(&nvm_lock);
+ list_add(&dev->devices, &nvm_devices);
+ up_write(&nvm_lock);
+
return 0;
err_init:
kfree(dev);
--
2.1.4
Both the nvm_register and nvm_init does a kfree(dev) on error. Make sure
to only free it once.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/lightnvm/core.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 40e6cfa..899f6b9 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -160,11 +160,6 @@ int nvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk)
}
EXPORT_SYMBOL(nvm_erase_blk);
-static void nvm_core_free(struct nvm_dev *dev)
-{
- kfree(dev);
-}
-
static int nvm_core_init(struct nvm_dev *dev)
{
struct nvm_id *id = &dev->identity;
@@ -223,8 +218,6 @@ static void nvm_free(struct nvm_dev *dev)
if (dev->mt)
dev->mt->unregister_mgr(dev);
-
- nvm_core_free(dev);
}
static int nvm_init(struct nvm_dev *dev)
@@ -351,11 +344,12 @@ void nvm_unregister(char *disk_name)
return;
}
- nvm_exit(dev);
-
down_write(&nvm_lock);
list_del(&dev->devices);
up_write(&nvm_lock);
+
+ nvm_exit(dev);
+ kfree(dev);
}
EXPORT_SYMBOL(nvm_unregister);
--
2.1.4
The linear and device specific address modes can be replaced with a
simple offset and bit length conversion that is generic across all
devices.
This both simplifies the specification and removes the special case for
qemu nvme, that previously relied on the linear address mapping.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/lightnvm/core.c | 3 +-
drivers/lightnvm/gennvm.c | 12 ++--
drivers/lightnvm/rrpc.c | 32 ++++++++-
drivers/nvme/host/lightnvm.c | 3 +-
include/linux/lightnvm.h | 154 ++++++++++---------------------------------
5 files changed, 73 insertions(+), 131 deletions(-)
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 899f6b9..790b1d7 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -174,8 +174,7 @@ static int nvm_core_init(struct nvm_dev *dev)
dev->sec_size = grp->csecs;
dev->oob_size = grp->sos;
dev->sec_per_pg = grp->fpg_sz / grp->csecs;
- dev->addr_mode = id->ppat;
- dev->addr_format = id->ppaf;
+ memcpy(&dev->ppaf, &id->ppaf, sizeof(struct nvm_addr_format));
dev->plane_mode = NVM_PLANE_SINGLE;
dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size;
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index 8cfc011..c0d0eb2 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -73,7 +73,7 @@ static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks,
struct nvm_block *blk;
int i;
- ppa = addr_to_generic_mode(gn->dev, ppa);
+ ppa = dev_to_generic_addr(gn->dev, ppa);
lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun];
for (i = 0; i < nr_blocks; i++) {
@@ -179,7 +179,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
ppa.ppa = 0;
ppa.g.ch = lun->vlun.chnl_id;
ppa.g.lun = lun->vlun.id;
- ppa = generic_to_addr_mode(dev, ppa);
+ ppa = generic_to_dev_addr(dev, ppa);
ret = dev->ops->get_bb_tbl(dev->q, ppa,
dev->blks_per_lun,
@@ -304,10 +304,10 @@ static void gennvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
if (rqd->nr_pages > 1) {
for (i = 0; i < rqd->nr_pages; i++)
- rqd->ppa_list[i] = addr_to_generic_mode(dev,
+ rqd->ppa_list[i] = dev_to_generic_addr(dev,
rqd->ppa_list[i]);
} else {
- rqd->ppa_addr = addr_to_generic_mode(dev, rqd->ppa_addr);
+ rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr);
}
}
@@ -317,10 +317,10 @@ static void gennvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
if (rqd->nr_pages > 1) {
for (i = 0; i < rqd->nr_pages; i++)
- rqd->ppa_list[i] = generic_to_addr_mode(dev,
+ rqd->ppa_list[i] = generic_to_dev_addr(dev,
rqd->ppa_list[i]);
} else {
- rqd->ppa_addr = generic_to_addr_mode(dev, rqd->ppa_addr);
+ rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr);
}
}
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
index 7ba64c8..75e59c3 100644
--- a/drivers/lightnvm/rrpc.c
+++ b/drivers/lightnvm/rrpc.c
@@ -123,12 +123,42 @@ static u64 block_to_addr(struct rrpc *rrpc, struct rrpc_block *rblk)
return blk->id * rrpc->dev->pgs_per_blk;
}
+static struct ppa_addr linear_to_generic_addr(struct nvm_dev *dev,
+ struct ppa_addr r)
+{
+ struct ppa_addr l;
+ int secs, pgs, blks, luns;
+ sector_t ppa = r.ppa;
+
+ l.ppa = 0;
+
+ div_u64_rem(ppa, dev->sec_per_pg, &secs);
+ l.g.sec = secs;
+
+ sector_div(ppa, dev->sec_per_pg);
+ div_u64_rem(ppa, dev->sec_per_blk, &pgs);
+ l.g.pg = pgs;
+
+ sector_div(ppa, dev->pgs_per_blk);
+ div_u64_rem(ppa, dev->blks_per_lun, &blks);
+ l.g.blk = blks;
+
+ sector_div(ppa, dev->blks_per_lun);
+ div_u64_rem(ppa, dev->luns_per_chnl, &luns);
+ l.g.lun = luns;
+
+ sector_div(ppa, dev->luns_per_chnl);
+ l.g.ch = ppa;
+
+ return l;
+}
+
static struct ppa_addr rrpc_ppa_to_gaddr(struct nvm_dev *dev, u64 addr)
{
struct ppa_addr paddr;
paddr.ppa = addr;
- return __linear_to_generic_addr(dev, paddr);
+ return linear_to_generic_addr(dev, paddr);
}
/* requires lun->lock taken */
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 52b311c..9069be8 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -198,8 +198,7 @@ struct nvme_nvm_id {
__le32 cap;
__le32 dom;
struct nvme_nvm_addr_format ppaf;
- __u8 ppat;
- __u8 resv[223];
+ __u8 resv[224];
struct nvme_nvm_id_group groups[4];
} __packed;
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index e6ef8aa..cbe288a 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -99,7 +99,6 @@ struct nvm_id {
u32 cap;
u32 dom;
struct nvm_addr_format ppaf;
- u8 ppat;
struct nvm_id_group groups[4];
} __packed;
@@ -119,39 +118,28 @@ struct nvm_tgt_instance {
#define NVM_VERSION_MINOR 0
#define NVM_VERSION_PATCH 0
-#define NVM_SEC_BITS (8)
-#define NVM_PL_BITS (6)
-#define NVM_PG_BITS (16)
#define NVM_BLK_BITS (16)
-#define NVM_LUN_BITS (10)
+#define NVM_PG_BITS (16)
+#define NVM_SEC_BITS (8)
+#define NVM_PL_BITS (8)
+#define NVM_LUN_BITS (8)
#define NVM_CH_BITS (8)
struct ppa_addr {
+ /* Generic structure for all addresses */
union {
- /* Channel-based PPA format in nand 4x2x2x2x8x10 */
- struct {
- u64 ch : 4;
- u64 sec : 2; /* 4 sectors per page */
- u64 pl : 2; /* 4 planes per LUN */
- u64 lun : 2; /* 4 LUNs per channel */
- u64 pg : 8; /* 256 pages per block */
- u64 blk : 10;/* 1024 blocks per plane */
- u64 resved : 36;
- } chnl;
-
- /* Generic structure for all addresses */
struct {
+ u64 blk : NVM_BLK_BITS;
+ u64 pg : NVM_PG_BITS;
u64 sec : NVM_SEC_BITS;
u64 pl : NVM_PL_BITS;
- u64 pg : NVM_PG_BITS;
- u64 blk : NVM_BLK_BITS;
u64 lun : NVM_LUN_BITS;
u64 ch : NVM_CH_BITS;
} g;
u64 ppa;
};
-} __packed;
+};
struct nvm_rq {
struct nvm_tgt_instance *ins;
@@ -259,8 +247,7 @@ struct nvm_dev {
int blks_per_lun;
int sec_size;
int oob_size;
- int addr_mode;
- struct nvm_addr_format addr_format;
+ struct nvm_addr_format ppaf;
/* Calculated/Cached values. These do not reflect the actual usable
* blocks at run-time.
@@ -286,118 +273,45 @@ struct nvm_dev {
char name[DISK_NAME_LEN];
};
-/* fallback conversion */
-static struct ppa_addr __generic_to_linear_addr(struct nvm_dev *dev,
- struct ppa_addr r)
+static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
+ struct ppa_addr r)
{
struct ppa_addr l;
- l.ppa = r.g.sec +
- r.g.pg * dev->sec_per_pg +
- r.g.blk * (dev->pgs_per_blk *
- dev->sec_per_pg) +
- r.g.lun * (dev->blks_per_lun *
- dev->pgs_per_blk *
- dev->sec_per_pg) +
- r.g.ch * (dev->blks_per_lun *
- dev->pgs_per_blk *
- dev->luns_per_chnl *
- dev->sec_per_pg);
+ 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;
return l;
}
-/* fallback conversion */
-static struct ppa_addr __linear_to_generic_addr(struct nvm_dev *dev,
- struct ppa_addr r)
+static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev,
+ struct ppa_addr r)
{
struct ppa_addr l;
- int secs, pgs, blks, luns;
- sector_t ppa = r.ppa;
- l.ppa = 0;
-
- div_u64_rem(ppa, dev->sec_per_pg, &secs);
- l.g.sec = secs;
-
- sector_div(ppa, dev->sec_per_pg);
- div_u64_rem(ppa, dev->sec_per_blk, &pgs);
- l.g.pg = pgs;
-
- sector_div(ppa, dev->pgs_per_blk);
- div_u64_rem(ppa, dev->blks_per_lun, &blks);
- l.g.blk = blks;
-
- sector_div(ppa, dev->blks_per_lun);
- div_u64_rem(ppa, dev->luns_per_chnl, &luns);
- l.g.lun = luns;
-
- sector_div(ppa, dev->luns_per_chnl);
- l.g.ch = ppa;
-
- return l;
-}
-
-static struct ppa_addr __generic_to_chnl_addr(struct ppa_addr r)
-{
- struct ppa_addr l;
-
- l.ppa = 0;
-
- l.chnl.sec = r.g.sec;
- l.chnl.pl = r.g.pl;
- l.chnl.pg = r.g.pg;
- l.chnl.blk = r.g.blk;
- l.chnl.lun = r.g.lun;
- l.chnl.ch = r.g.ch;
+ /*
+ * (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));
return l;
}
-static struct ppa_addr __chnl_to_generic_addr(struct ppa_addr r)
-{
- struct ppa_addr l;
-
- l.ppa = 0;
-
- l.g.sec = r.chnl.sec;
- l.g.pl = r.chnl.pl;
- l.g.pg = r.chnl.pg;
- l.g.blk = r.chnl.blk;
- l.g.lun = r.chnl.lun;
- l.g.ch = r.chnl.ch;
-
- return l;
-}
-
-static inline struct ppa_addr addr_to_generic_mode(struct nvm_dev *dev,
- struct ppa_addr gppa)
-{
- switch (dev->addr_mode) {
- case NVM_ADDRMODE_LINEAR:
- return __linear_to_generic_addr(dev, gppa);
- case NVM_ADDRMODE_CHANNEL:
- return __chnl_to_generic_addr(gppa);
- default:
- BUG();
- }
- return gppa;
-}
-
-static inline struct ppa_addr generic_to_addr_mode(struct nvm_dev *dev,
- struct ppa_addr gppa)
-{
- switch (dev->addr_mode) {
- case NVM_ADDRMODE_LINEAR:
- return __generic_to_linear_addr(dev, gppa);
- case NVM_ADDRMODE_CHANNEL:
- return __generic_to_chnl_addr(gppa);
- default:
- BUG();
- }
- return gppa;
-}
-
static inline int ppa_empty(struct ppa_addr ppa_addr)
{
return (ppa_addr.ppa == ADDR_EMPTY);
--
2.1.4
The ppa format was not copied from the NVMe specific ppa format to the
lightnvm specific ppa format. This led to the ppa format not being
communicated to the layers above.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/nvme/host/lightnvm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 9069be8..fd37123 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -300,6 +300,8 @@ static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id)
nvm_id->cgrps = nvme_nvm_id->cgrps;
nvm_id->cap = le32_to_cpu(nvme_nvm_id->cap);
nvm_id->dom = le32_to_cpu(nvme_nvm_id->dom);
+ memcpy(&nvm_id->ppaf, &nvme_nvm_id->ppaf,
+ sizeof(struct nvme_nvm_addr_format));
ret = init_grps(nvm_id, nvme_nvm_id);
out:
--
2.1.4
The specification was updated the remove the double word just after
number of configuration groups and capabilities. Update the identify
structure to reflect it.
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/nvme/host/lightnvm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index fd37123..7e82fe3 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -194,11 +194,11 @@ struct nvme_nvm_id {
__u8 ver_id;
__u8 vmnt;
__u8 cgrps;
- __u8 res[5];
+ __u8 res;
__le32 cap;
__le32 dom;
struct nvme_nvm_addr_format ppaf;
- __u8 resv[224];
+ __u8 resv[228];
struct nvme_nvm_id_group groups[4];
} __packed;
--
2.1.4
From: Javier González <[email protected]>
This prevents outstanding IOs to be sent for completion to target after
the target has been removed. The flow is now: stop new IOs > cleanup
queue > remove target.
Signed-off-by: Javier Gonzalez <[email protected]>
Signed-off-by: Matias Bjørling <[email protected]>
---
drivers/lightnvm/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 790b1d7..8a556f3 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -460,11 +460,11 @@ static void nvm_remove_target(struct nvm_target *t)
lockdep_assert_held(&nvm_lock);
del_gendisk(tdisk);
+ blk_cleanup_queue(q);
+
if (tt->exit)
tt->exit(tdisk->private_data);
- blk_cleanup_queue(q);
-
put_disk(tdisk);
list_del(&t->list);
--
2.1.4
On 11/16/2015 07:34 AM, Matias Bjørling wrote:
> Hi Jens,
>
> This is the patches targeted for -rc2 of 4.4.
>
> Ten of the patches fix bugs and small specification updates. While the
> last two are larger patches. They are necessary because of specification
> changes. The updates are applied now before it is set in stone for 4.4
> (or at least makes it a lot harder to change)
>
> Patch 1: Adds the linux-block list to the maintainers list for LightNVM.
> Patch 2: Fixes a ushort bug reported by Geert.
> Patch 3: Updates the implementation to support the new bad block table
> format.
> Patch 4-9: Small fixes.
> Patch 10: The specification had support for both linear and device
> specific addressing. It was replaced by ppa format, that
> defines the device ppa format used by the specific device.
> This patch adds the support and removes the previous two
> modes.
> Patch 11-12: Two small cleanups to the lightnvm nvme integration.
> Caused by specification changes.
>
> Patches 3 to 12 is the first time they are posted to the list for
> review.
>
> Will you pick up the patches when convenient (and reviewed):
>
> [email protected]:OpenChannelSSD/linux.git for-jens
>
> I'll update the for-jens branch and post a separate patch if any
> fixes is applied to the patches.
Applied, thanks.
--
Jens Axboe