summaryrefslogtreecommitdiffstats
path: root/drivers/nvme/host/lightnvm.c
diff options
context:
space:
mode:
authorLinus Torvalds2016-03-19 01:13:31 +0100
committerLinus Torvalds2016-03-19 01:13:31 +0100
commit237045fc3c67d44088f767dca5a9fa30815eba62 (patch)
tree50773de6320e4b3358e3935c2f3c6f93d0dc93f3 /drivers/nvme/host/lightnvm.c
parentMerge branch 'for-4.6/core' of git://git.kernel.dk/linux-block (diff)
parentNVMe: Expose ns wwid through single sysfs entry (diff)
downloadkernel-qcow2-linux-237045fc3c67d44088f767dca5a9fa30815eba62.tar.gz
kernel-qcow2-linux-237045fc3c67d44088f767dca5a9fa30815eba62.tar.xz
kernel-qcow2-linux-237045fc3c67d44088f767dca5a9fa30815eba62.zip
Merge branch 'for-4.6/drivers' of git://git.kernel.dk/linux-block
Pull block driver updates from Jens Axboe: "This is the block driver pull request for this merge window. It sits on top of for-4.6/core, that was just sent out. This contains: - A set of fixes for lightnvm. One from Alan, fixing an overflow, and the rest from the usual suspects, Javier and Matias. - A set of fixes for nbd from Markus and Dan, and a fixup from Arnd for correct usage of the signed 64-bit divider. - A set of bug fixes for the Micron mtip32xx, from Asai. - A fix for the brd discard handling from Bart. - Update the maintainers entry for cciss, since that hardware has transferred ownership. - Three bug fixes for bcache from Eric Wheeler. - Set of fixes for xen-blk{back,front} from Jan and Konrad. - Removal of the cpqarray driver. It has been disabled in Kconfig since 2013, and we were initially scheduled to remove it in 3.15. - Various updates and fixes for NVMe, with the most important being: - Removal of the per-device NVMe thread, replacing that with a watchdog timer instead. From Christoph. - Exposing the namespace WWID through sysfs, from Keith. - Set of cleanups from Ming Lin. - Logging the controller device name instead of the underlying PCI device name, from Sagi. - And a bunch of fixes and optimizations from the usual suspects in this area" * 'for-4.6/drivers' of git://git.kernel.dk/linux-block: (49 commits) NVMe: Expose ns wwid through single sysfs entry drivers:block: cpqarray clean up brd: Fix discard request processing cpqarray: remove it from the kernel cciss: update MAINTAINERS NVMe: Remove unused sq_head read in completion path bcache: fix cache_set_flush() NULL pointer dereference on OOM bcache: cleaned up error handling around register_cache() bcache: fix race of writeback thread starting before complete initialization NVMe: Create discard zero quirk white list nbd: use correct div_s64 helper mtip32xx: remove unneeded variable in mtip_cmd_timeout() lightnvm: generalize rrpc ppa calculations lightnvm: remove struct nvm_dev->total_blocks lightnvm: rename ->nr_pages to ->nr_sects lightnvm: update closed list outside of intr context xen/blback: Fit the important information of the thread in 17 characters lightnvm: fold get bb tbl when using dual/quad plane mode lightnvm: fix up nonsensical configure overrun checking xen-blkback: advertise indirect segment support earlier ...
Diffstat (limited to 'drivers/nvme/host/lightnvm.c')
-rw-r--r--drivers/nvme/host/lightnvm.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 6bb15e4926dc..42a01a931989 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -379,8 +379,31 @@ out:
return ret;
}
+static void nvme_nvm_bb_tbl_fold(struct nvm_dev *nvmdev,
+ int nr_dst_blks, u8 *dst_blks,
+ int nr_src_blks, u8 *src_blks)
+{
+ int blk, offset, pl, blktype;
+
+ for (blk = 0; blk < nr_dst_blks; blk++) {
+ offset = blk * nvmdev->plane_mode;
+ blktype = src_blks[offset];
+
+ /* Bad blocks on any planes take precedence over other types */
+ for (pl = 0; pl < nvmdev->plane_mode; pl++) {
+ if (src_blks[offset + pl] &
+ (NVM_BLK_T_BAD|NVM_BLK_T_GRWN_BAD)) {
+ blktype = src_blks[offset + pl];
+ break;
+ }
+ }
+
+ dst_blks[blk] = blktype;
+ }
+}
+
static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
- int nr_blocks, nvm_bb_update_fn *update_bbtbl,
+ int nr_dst_blks, nvm_bb_update_fn *update_bbtbl,
void *priv)
{
struct request_queue *q = nvmdev->q;
@@ -388,7 +411,9 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
struct nvme_ctrl *ctrl = ns->ctrl;
struct nvme_nvm_command c = {};
struct nvme_nvm_bb_tbl *bb_tbl;
- int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blocks;
+ u8 *dst_blks = NULL;
+ int nr_src_blks = nr_dst_blks * nvmdev->plane_mode;
+ int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_src_blks;
int ret = 0;
c.get_bb.opcode = nvme_nvm_admin_get_bb_tbl;
@@ -399,6 +424,12 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
if (!bb_tbl)
return -ENOMEM;
+ dst_blks = kzalloc(nr_dst_blks, GFP_KERNEL);
+ if (!dst_blks) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
ret = nvme_submit_sync_cmd(ctrl->admin_q, (struct nvme_command *)&c,
bb_tbl, tblsz);
if (ret) {
@@ -420,16 +451,21 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
goto out;
}
- if (le32_to_cpu(bb_tbl->tblks) != nr_blocks) {
+ if (le32_to_cpu(bb_tbl->tblks) != nr_src_blks) {
ret = -EINVAL;
dev_err(ctrl->dev, "bbt unsuspected blocks returned (%u!=%u)",
- le32_to_cpu(bb_tbl->tblks), nr_blocks);
+ le32_to_cpu(bb_tbl->tblks), nr_src_blks);
goto out;
}
+ nvme_nvm_bb_tbl_fold(nvmdev, nr_dst_blks, dst_blks,
+ nr_src_blks, bb_tbl->blk);
+
ppa = dev_to_generic_addr(nvmdev, ppa);
- ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv);
+ ret = update_bbtbl(ppa, nr_dst_blks, dst_blks, priv);
+
out:
+ kfree(dst_blks);
kfree(bb_tbl);
return ret;
}