]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/nvme/host/core.c
block: ensure bios return from blk_get_request are properly initialized
[karo-tx-linux.git] / drivers / nvme / host / core.c
index f5676c69842a43ebc11e5785df72ec19ca9840a2..9f0ec3b4659fcfeeede6cee056fc19e6e22be8b9 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/unaligned.h>
 
 #include "nvme.h"
+#include "fabrics.h"
 
 #define NVME_MINORS            (1U << MINORBITS)
 
@@ -47,8 +48,10 @@ unsigned char shutdown_timeout = 5;
 module_param(shutdown_timeout, byte, 0644);
 MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
 
-static int nvme_major;
-module_param(nvme_major, int, 0);
+unsigned int nvme_max_retries = 5;
+module_param_named(max_retries, nvme_max_retries, uint, 0644);
+MODULE_PARM_DESC(max_retries, "max number of retries a command may have");
+EXPORT_SYMBOL_GPL(nvme_max_retries);
 
 static int nvme_char_major;
 module_param(nvme_char_major, int, 0);
@@ -87,6 +90,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                switch (old_state) {
                case NVME_CTRL_NEW:
                case NVME_CTRL_RESETTING:
+               case NVME_CTRL_RECONNECTING:
                        changed = true;
                        /* FALLTHRU */
                default:
@@ -96,6 +100,16 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
        case NVME_CTRL_RESETTING:
                switch (old_state) {
                case NVME_CTRL_NEW:
+               case NVME_CTRL_LIVE:
+               case NVME_CTRL_RECONNECTING:
+                       changed = true;
+                       /* FALLTHRU */
+               default:
+                       break;
+               }
+               break;
+       case NVME_CTRL_RECONNECTING:
+               switch (old_state) {
                case NVME_CTRL_LIVE:
                        changed = true;
                        /* FALLTHRU */
@@ -107,6 +121,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                switch (old_state) {
                case NVME_CTRL_LIVE:
                case NVME_CTRL_RESETTING:
+               case NVME_CTRL_RECONNECTING:
                        changed = true;
                        /* FALLTHRU */
                default:
@@ -207,10 +222,6 @@ struct request *nvme_alloc_request(struct request_queue *q,
 
        req->cmd_type = REQ_TYPE_DRV_PRIV;
        req->cmd_flags |= REQ_FAILFAST_DRIVER;
-       req->__data_len = 0;
-       req->__sector = (sector_t) -1;
-       req->bio = req->biotail = NULL;
-
        req->cmd = (unsigned char *)cmd;
        req->cmd_len = sizeof(struct nvme_command);
 
@@ -463,6 +474,74 @@ int nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
                        result, timeout);
 }
 
+static void nvme_keep_alive_end_io(struct request *rq, int error)
+{
+       struct nvme_ctrl *ctrl = rq->end_io_data;
+
+       blk_mq_free_request(rq);
+
+       if (error) {
+               dev_err(ctrl->device,
+                       "failed nvme_keep_alive_end_io error=%d\n", error);
+               return;
+       }
+
+       schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ);
+}
+
+static int nvme_keep_alive(struct nvme_ctrl *ctrl)
+{
+       struct nvme_command c;
+       struct request *rq;
+
+       memset(&c, 0, sizeof(c));
+       c.common.opcode = nvme_admin_keep_alive;
+
+       rq = nvme_alloc_request(ctrl->admin_q, &c, BLK_MQ_REQ_RESERVED,
+                       NVME_QID_ANY);
+       if (IS_ERR(rq))
+               return PTR_ERR(rq);
+
+       rq->timeout = ctrl->kato * HZ;
+       rq->end_io_data = ctrl;
+
+       blk_execute_rq_nowait(rq->q, NULL, rq, 0, nvme_keep_alive_end_io);
+
+       return 0;
+}
+
+static void nvme_keep_alive_work(struct work_struct *work)
+{
+       struct nvme_ctrl *ctrl = container_of(to_delayed_work(work),
+                       struct nvme_ctrl, ka_work);
+
+       if (nvme_keep_alive(ctrl)) {
+               /* allocation failure, reset the controller */
+               dev_err(ctrl->device, "keep-alive failed\n");
+               ctrl->ops->reset_ctrl(ctrl);
+               return;
+       }
+}
+
+void nvme_start_keep_alive(struct nvme_ctrl *ctrl)
+{
+       if (unlikely(ctrl->kato == 0))
+               return;
+
+       INIT_DELAYED_WORK(&ctrl->ka_work, nvme_keep_alive_work);
+       schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ);
+}
+EXPORT_SYMBOL_GPL(nvme_start_keep_alive);
+
+void nvme_stop_keep_alive(struct nvme_ctrl *ctrl)
+{
+       if (unlikely(ctrl->kato == 0))
+               return;
+
+       cancel_delayed_work_sync(&ctrl->ka_work);
+}
+EXPORT_SYMBOL_GPL(nvme_stop_keep_alive);
+
 int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
 {
        struct nvme_command c = { };
@@ -524,7 +603,7 @@ int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
        memset(&c, 0, sizeof(c));
        c.features.opcode = nvme_admin_get_features;
        c.features.nsid = cpu_to_le32(nsid);
-       c.features.prp1 = cpu_to_le64(dma_addr);
+       c.features.dptr.prp1 = cpu_to_le64(dma_addr);
        c.features.fid = cpu_to_le32(fid);
 
        ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, NULL, 0, 0,
@@ -543,7 +622,7 @@ int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
 
        memset(&c, 0, sizeof(c));
        c.features.opcode = nvme_admin_set_features;
-       c.features.prp1 = cpu_to_le64(dma_addr);
+       c.features.dptr.prp1 = cpu_to_le64(dma_addr);
        c.features.fid = cpu_to_le32(fid);
        c.features.dword11 = cpu_to_le32(dword11);
 
@@ -1028,6 +1107,15 @@ int nvme_disable_ctrl(struct nvme_ctrl *ctrl, u64 cap)
        ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config);
        if (ret)
                return ret;
+
+       /* Checking for ctrl->tagset is a trick to avoid sleeping on module
+        * load, since we only need the quirk on reset_controller. Notice
+        * that the HGST device needs this delay only in firmware activation
+        * procedure; unfortunately we have no (easy) way to verify this.
+        */
+       if ((ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY) && ctrl->tagset)
+               msleep(NVME_QUIRK_DELAY_AMOUNT);
+
        return nvme_wait_ready(ctrl, cap, false);
 }
 EXPORT_SYMBOL_GPL(nvme_disable_ctrl);
@@ -1178,9 +1266,33 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
        }
 
        nvme_set_queue_limits(ctrl, ctrl->admin_q);
+       ctrl->sgls = le32_to_cpu(id->sgls);
+       ctrl->kas = le16_to_cpu(id->kas);
+
+       if (ctrl->ops->is_fabrics) {
+               ctrl->icdoff = le16_to_cpu(id->icdoff);
+               ctrl->ioccsz = le32_to_cpu(id->ioccsz);
+               ctrl->iorcsz = le32_to_cpu(id->iorcsz);
+               ctrl->maxcmd = le16_to_cpu(id->maxcmd);
+
+               /*
+                * In fabrics we need to verify the cntlid matches the
+                * admin connect
+                */
+               if (ctrl->cntlid != le16_to_cpu(id->cntlid))
+                       ret = -EINVAL;
+
+               if (!ctrl->opts->discovery_nqn && !ctrl->kas) {
+                       dev_err(ctrl->dev,
+                               "keep-alive support is mandatory for fabrics\n");
+                       ret = -EINVAL;
+               }
+       } else {
+               ctrl->cntlid = le16_to_cpu(id->cntlid);
+       }
 
        kfree(id);
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(nvme_init_identify);
 
@@ -1555,12 +1667,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
        nvme_set_queue_limits(ctrl, ns->queue);
 
-       disk->major = nvme_major;
-       disk->first_minor = 0;
        disk->fops = &nvme_fops;
        disk->private_data = ns;
        disk->queue = ns->queue;
-       disk->driverfs_dev = ctrl->device;
        disk->flags = GENHD_FL_EXT_DEVT;
        sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
 
@@ -1572,7 +1681,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        if (ns->type == NVME_NS_LIGHTNVM)
                return;
 
-       add_disk(ns->disk);
+       device_add_disk(ctrl->device, ns->disk);
        if (sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
                                        &nvme_ns_attr_group))
                pr_warn("%s: failed to create sysfs group for identification\n",
@@ -1967,16 +2076,10 @@ int __init nvme_core_init(void)
 {
        int result;
 
-       result = register_blkdev(nvme_major, "nvme");
-       if (result < 0)
-               return result;
-       else if (result > 0)
-               nvme_major = result;
-
        result = __register_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme",
                                                        &nvme_dev_fops);
        if (result < 0)
-               goto unregister_blkdev;
+               return result;
        else if (result > 0)
                nvme_char_major = result;
 
@@ -1990,8 +2093,6 @@ int __init nvme_core_init(void)
 
  unregister_chrdev:
        __unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
- unregister_blkdev:
-       unregister_blkdev(nvme_major, "nvme");
        return result;
 }
 
@@ -1999,7 +2100,6 @@ void nvme_core_exit(void)
 {
        class_destroy(nvme_class);
        __unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
-       unregister_blkdev(nvme_major, "nvme");
 }
 
 MODULE_LICENSE("GPL");