OSDN Git Service

nvme: remove nvme_alloc_request and nvme_alloc_request_qid
[uclinux-h8/linux.git] / drivers / nvme / host / core.c
index 5e0bfda..c868015 100644 (file)
@@ -299,6 +299,37 @@ static void nvme_retry_req(struct request *req)
        blk_mq_delay_kick_requeue_list(req->q, delay);
 }
 
+static void nvme_log_error(struct request *req)
+{
+       struct nvme_ns *ns = req->q->queuedata;
+       struct nvme_request *nr = nvme_req(req);
+
+       if (ns) {
+               pr_err_ratelimited("%s: %s(0x%x) @ LBA %llu, %llu blocks, %s (sct 0x%x / sc 0x%x) %s%s\n",
+                      ns->disk ? ns->disk->disk_name : "?",
+                      nvme_get_opcode_str(nr->cmd->common.opcode),
+                      nr->cmd->common.opcode,
+                      (unsigned long long)nvme_sect_to_lba(ns, blk_rq_pos(req)),
+                      (unsigned long long)blk_rq_bytes(req) >> ns->lba_shift,
+                      nvme_get_error_status_str(nr->status),
+                      nr->status >> 8 & 7,     /* Status Code Type */
+                      nr->status & 0xff,       /* Status Code */
+                      nr->status & NVME_SC_MORE ? "MORE " : "",
+                      nr->status & NVME_SC_DNR  ? "DNR "  : "");
+               return;
+       }
+
+       pr_err_ratelimited("%s: %s(0x%x), %s (sct 0x%x / sc 0x%x) %s%s\n",
+                          dev_name(nr->ctrl->device),
+                          nvme_get_admin_opcode_str(nr->cmd->common.opcode),
+                          nr->cmd->common.opcode,
+                          nvme_get_error_status_str(nr->status),
+                          nr->status >> 8 & 7, /* Status Code Type */
+                          nr->status & 0xff,   /* Status Code */
+                          nr->status & NVME_SC_MORE ? "MORE " : "",
+                          nr->status & NVME_SC_DNR  ? "DNR "  : "");
+}
+
 enum nvme_disposition {
        COMPLETE,
        RETRY,
@@ -339,6 +370,8 @@ static inline void nvme_end_req(struct request *req)
 {
        blk_status_t status = nvme_error_status(nvme_req(req)->status);
 
+       if (unlikely(nvme_req(req)->status != NVME_SC_SUCCESS))
+               nvme_log_error(req);
        nvme_end_req_zoned(req);
        nvme_trace_bio_complete(req);
        blk_mq_end_request(req, status);
@@ -561,7 +594,7 @@ static void nvme_free_ns_head(struct kref *ref)
                container_of(ref, struct nvme_ns_head, ref);
 
        nvme_mpath_remove_disk(head);
-       ida_simple_remove(&head->subsys->ns_ida, head->instance);
+       ida_free(&head->subsys->ns_ida, head->instance);
        cleanup_srcu_struct(&head->srcu);
        nvme_put_subsystem(head->subsys);
        kfree(head);
@@ -606,13 +639,8 @@ static inline void nvme_clear_nvme_request(struct request *req)
        req->rq_flags |= RQF_DONTPREP;
 }
 
-static inline unsigned int nvme_req_op(struct nvme_command *cmd)
-{
-       return nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
-}
-
-static inline void nvme_init_request(struct request *req,
-               struct nvme_command *cmd)
+/* initialize a passthrough request */
+void nvme_init_request(struct request *req, struct nvme_command *cmd)
 {
        if (req->q->queuedata)
                req->timeout = NVME_IO_TIMEOUT;
@@ -628,30 +656,7 @@ static inline void nvme_init_request(struct request *req,
        nvme_clear_nvme_request(req);
        memcpy(nvme_req(req)->cmd, cmd, sizeof(*cmd));
 }
-
-struct request *nvme_alloc_request(struct request_queue *q,
-               struct nvme_command *cmd, blk_mq_req_flags_t flags)
-{
-       struct request *req;
-
-       req = blk_mq_alloc_request(q, nvme_req_op(cmd), flags);
-       if (!IS_ERR(req))
-               nvme_init_request(req, cmd);
-       return req;
-}
-EXPORT_SYMBOL_GPL(nvme_alloc_request);
-
-static struct request *nvme_alloc_request_qid(struct request_queue *q,
-               struct nvme_command *cmd, blk_mq_req_flags_t flags, int qid)
-{
-       struct request *req;
-
-       req = blk_mq_alloc_request_hctx(q, nvme_req_op(cmd), flags,
-                       qid ? qid - 1 : 0);
-       if (!IS_ERR(req))
-               nvme_init_request(req, cmd);
-       return req;
-}
+EXPORT_SYMBOL_GPL(nvme_init_request);
 
 /*
  * For something we're not in a state to send to the device the default action
@@ -757,6 +762,7 @@ static int nvme_get_stream_params(struct nvme_ctrl *ctrl,
 static int nvme_configure_directives(struct nvme_ctrl *ctrl)
 {
        struct streams_directive_params s;
+       u16 nssa;
        int ret;
 
        if (!(ctrl->oacs & NVME_CTRL_OACS_DIRECTIVES))
@@ -772,14 +778,16 @@ static int nvme_configure_directives(struct nvme_ctrl *ctrl)
        if (ret)
                goto out_disable_stream;
 
-       ctrl->nssa = le16_to_cpu(s.nssa);
-       if (ctrl->nssa < BLK_MAX_WRITE_HINTS - 1) {
+       nssa = le16_to_cpu(s.nssa);
+       if (nssa < BLK_MAX_WRITE_HINTS - 1) {
                dev_info(ctrl->device, "too few streams (%u) available\n",
-                                       ctrl->nssa);
+                                       nssa);
+               /* this condition is not an error: streams are optional */
+               ret = 0;
                goto out_disable_stream;
        }
 
-       ctrl->nr_streams = min_t(u16, ctrl->nssa, BLK_MAX_WRITE_HINTS - 1);
+       ctrl->nr_streams = min_t(u16, nssa, BLK_MAX_WRITE_HINTS - 1);
        dev_info(ctrl->device, "Using %u streams\n", ctrl->nr_streams);
        return 0;
 
@@ -1049,8 +1057,7 @@ EXPORT_SYMBOL_GPL(nvme_setup_cmd);
  * >0: nvme controller's cqe status response
  * <0: kernel error in lieu of controller response
  */
-static int nvme_execute_rq(struct gendisk *disk, struct request *rq,
-               bool at_head)
+static int nvme_execute_rq(struct request *rq, bool at_head)
 {
        blk_status_t status;
 
@@ -1075,11 +1082,14 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
        int ret;
 
        if (qid == NVME_QID_ANY)
-               req = nvme_alloc_request(q, cmd, flags);
+               req = blk_mq_alloc_request(q, nvme_req_op(cmd), flags);
        else
-               req = nvme_alloc_request_qid(q, cmd, flags, qid);
+               req = blk_mq_alloc_request_hctx(q, nvme_req_op(cmd), flags,
+                                               qid ? qid - 1 : 0);
+
        if (IS_ERR(req))
                return PTR_ERR(req);
+       nvme_init_request(req, cmd);
 
        if (timeout)
                req->timeout = timeout;
@@ -1090,7 +1100,7 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                        goto out;
        }
 
-       ret = nvme_execute_rq(NULL, req, at_head);
+       ret = nvme_execute_rq(req, at_head);
        if (result && ret >= 0)
                *result = nvme_req(req)->result;
  out:
@@ -1206,12 +1216,11 @@ int nvme_execute_passthru_rq(struct request *rq)
        struct nvme_command *cmd = nvme_req(rq)->cmd;
        struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl;
        struct nvme_ns *ns = rq->q->queuedata;
-       struct gendisk *disk = ns ? ns->disk : NULL;
        u32 effects;
        int  ret;
 
        effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
-       ret = nvme_execute_rq(disk, rq, false);
+       ret = nvme_execute_rq(rq, false);
        if (effects) /* nothing to be done for zero cmd effects */
                nvme_passthru_end(ctrl, effects, cmd, ret);
 
@@ -1270,14 +1279,15 @@ static void nvme_keep_alive_work(struct work_struct *work)
                return;
        }
 
-       rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd,
-                               BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
+       rq = blk_mq_alloc_request(ctrl->admin_q, nvme_req_op(&ctrl->ka_cmd),
+                                 BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
        if (IS_ERR(rq)) {
                /* allocation failure, reset the controller */
                dev_err(ctrl->device, "keep-alive failed: %ld\n", PTR_ERR(rq));
                nvme_reset_ctrl(ctrl);
                return;
        }
+       nvme_init_request(rq, &ctrl->ka_cmd);
 
        rq->timeout = ctrl->kato * HZ;
        rq->end_io_data = ctrl;
@@ -1682,13 +1692,6 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns)
                blk_queue_max_write_zeroes_sectors(queue, UINT_MAX);
 }
 
-static bool nvme_ns_ids_valid(struct nvme_ns_ids *ids)
-{
-       return !uuid_is_null(&ids->uuid) ||
-               memchr_inv(ids->nguid, 0, sizeof(ids->nguid)) ||
-               memchr_inv(ids->eui64, 0, sizeof(ids->eui64));
-}
-
 static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b)
 {
        return uuid_equal(&a->uuid, &b->uuid) &&
@@ -1979,7 +1982,7 @@ static char nvme_pr_type(enum pr_type type)
        default:
                return 0;
        }
-};
+}
 
 static int nvme_send_ns_head_pr_command(struct block_device *bdev,
                struct nvme_command *c, u8 data[16])
@@ -2567,7 +2570,7 @@ static void nvme_release_subsystem(struct device *dev)
                container_of(dev, struct nvme_subsystem, dev);
 
        if (subsys->instance >= 0)
-               ida_simple_remove(&nvme_instance_ida, subsys->instance);
+               ida_free(&nvme_instance_ida, subsys->instance);
        kfree(subsys);
 }
 
@@ -2992,6 +2995,9 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
        ctrl->max_namespaces = le32_to_cpu(id->mnan);
        ctrl->ctratt = le32_to_cpu(id->ctratt);
 
+       ctrl->cntrltype = id->cntrltype;
+       ctrl->dctype = id->dctype;
+
        if (id->rtd3e) {
                /* us -> s */
                u32 transition_time = le32_to_cpu(id->rtd3e) / USEC_PER_SEC;
@@ -3525,6 +3531,40 @@ static ssize_t nvme_ctrl_fast_io_fail_tmo_store(struct device *dev,
 static DEVICE_ATTR(fast_io_fail_tmo, S_IRUGO | S_IWUSR,
        nvme_ctrl_fast_io_fail_tmo_show, nvme_ctrl_fast_io_fail_tmo_store);
 
+static ssize_t cntrltype_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       static const char * const type[] = {
+               [NVME_CTRL_IO] = "io\n",
+               [NVME_CTRL_DISC] = "discovery\n",
+               [NVME_CTRL_ADMIN] = "admin\n",
+       };
+       struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+       if (ctrl->cntrltype > NVME_CTRL_ADMIN || !type[ctrl->cntrltype])
+               return sysfs_emit(buf, "reserved\n");
+
+       return sysfs_emit(buf, type[ctrl->cntrltype]);
+}
+static DEVICE_ATTR_RO(cntrltype);
+
+static ssize_t dctype_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       static const char * const type[] = {
+               [NVME_DCTYPE_NOT_REPORTED] = "none\n",
+               [NVME_DCTYPE_DDC] = "ddc\n",
+               [NVME_DCTYPE_CDC] = "cdc\n",
+       };
+       struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+       if (ctrl->dctype > NVME_DCTYPE_CDC || !type[ctrl->dctype])
+               return sysfs_emit(buf, "reserved\n");
+
+       return sysfs_emit(buf, type[ctrl->dctype]);
+}
+static DEVICE_ATTR_RO(dctype);
+
 static struct attribute *nvme_dev_attrs[] = {
        &dev_attr_reset_controller.attr,
        &dev_attr_rescan_controller.attr,
@@ -3546,6 +3586,8 @@ static struct attribute *nvme_dev_attrs[] = {
        &dev_attr_reconnect_delay.attr,
        &dev_attr_fast_io_fail_tmo.attr,
        &dev_attr_kato.attr,
+       &dev_attr_cntrltype.attr,
+       &dev_attr_dctype.attr,
        NULL
 };
 
@@ -3600,16 +3642,24 @@ static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsys,
        return NULL;
 }
 
-static int __nvme_check_ids(struct nvme_subsystem *subsys,
-               struct nvme_ns_head *new)
+static int nvme_subsys_check_duplicate_ids(struct nvme_subsystem *subsys,
+               struct nvme_ns_ids *ids)
 {
+       bool has_uuid = !uuid_is_null(&ids->uuid);
+       bool has_nguid = memchr_inv(ids->nguid, 0, sizeof(ids->nguid));
+       bool has_eui64 = memchr_inv(ids->eui64, 0, sizeof(ids->eui64));
        struct nvme_ns_head *h;
 
        lockdep_assert_held(&subsys->lock);
 
        list_for_each_entry(h, &subsys->nsheads, entry) {
-               if (nvme_ns_ids_valid(&new->ids) &&
-                   nvme_ns_ids_equal(&new->ids, &h->ids))
+               if (has_uuid && uuid_equal(&ids->uuid, &h->ids.uuid))
+                       return -EINVAL;
+               if (has_nguid &&
+                   memcmp(&ids->nguid, &h->ids.nguid, sizeof(ids->nguid)) == 0)
+                       return -EINVAL;
+               if (has_eui64 &&
+                   memcmp(&ids->eui64, &h->ids.eui64, sizeof(ids->eui64)) == 0)
                        return -EINVAL;
        }
 
@@ -3618,7 +3668,7 @@ static int __nvme_check_ids(struct nvme_subsystem *subsys,
 
 static void nvme_cdev_rel(struct device *dev)
 {
-       ida_simple_remove(&nvme_ns_chr_minor_ida, MINOR(dev->devt));
+       ida_free(&nvme_ns_chr_minor_ida, MINOR(dev->devt));
 }
 
 void nvme_cdev_del(struct cdev *cdev, struct device *cdev_device)
@@ -3632,7 +3682,7 @@ int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
 {
        int minor, ret;
 
-       minor = ida_simple_get(&nvme_ns_chr_minor_ida, 0, 0, GFP_KERNEL);
+       minor = ida_alloc(&nvme_ns_chr_minor_ida, GFP_KERNEL);
        if (minor < 0)
                return minor;
        cdev_device->devt = MKDEV(MAJOR(nvme_ns_chr_devt), minor);
@@ -3695,7 +3745,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
        head = kzalloc(size, GFP_KERNEL);
        if (!head)
                goto out;
-       ret = ida_simple_get(&ctrl->subsys->ns_ida, 1, 0, GFP_KERNEL);
+       ret = ida_alloc_min(&ctrl->subsys->ns_ida, 1, GFP_KERNEL);
        if (ret < 0)
                goto out_free_head;
        head->instance = ret;
@@ -3708,13 +3758,6 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
        head->ids = *ids;
        kref_init(&head->ref);
 
-       ret = __nvme_check_ids(ctrl->subsys, head);
-       if (ret) {
-               dev_err(ctrl->device,
-                       "duplicate IDs for nsid %d\n", nsid);
-               goto out_cleanup_srcu;
-       }
-
        if (head->ids.csi) {
                ret = nvme_get_effects_log(ctrl, head->ids.csi, &head->effects);
                if (ret)
@@ -3734,7 +3777,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
 out_cleanup_srcu:
        cleanup_srcu_struct(&head->srcu);
 out_ida_remove:
-       ida_simple_remove(&ctrl->subsys->ns_ida, head->instance);
+       ida_free(&ctrl->subsys->ns_ida, head->instance);
 out_free_head:
        kfree(head);
 out:
@@ -3743,16 +3786,56 @@ out:
        return ERR_PTR(ret);
 }
 
+static int nvme_global_check_duplicate_ids(struct nvme_subsystem *this,
+               struct nvme_ns_ids *ids)
+{
+       struct nvme_subsystem *s;
+       int ret = 0;
+
+       /*
+        * Note that this check is racy as we try to avoid holding the global
+        * lock over the whole ns_head creation.  But it is only intended as
+        * a sanity check anyway.
+        */
+       mutex_lock(&nvme_subsystems_lock);
+       list_for_each_entry(s, &nvme_subsystems, entry) {
+               if (s == this)
+                       continue;
+               mutex_lock(&s->lock);
+               ret = nvme_subsys_check_duplicate_ids(s, ids);
+               mutex_unlock(&s->lock);
+               if (ret)
+                       break;
+       }
+       mutex_unlock(&nvme_subsystems_lock);
+
+       return ret;
+}
+
 static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
                struct nvme_ns_ids *ids, bool is_shared)
 {
        struct nvme_ctrl *ctrl = ns->ctrl;
        struct nvme_ns_head *head = NULL;
-       int ret = 0;
+       int ret;
+
+       ret = nvme_global_check_duplicate_ids(ctrl->subsys, ids);
+       if (ret) {
+               dev_err(ctrl->device,
+                       "globally duplicate IDs for nsid %d\n", nsid);
+               return ret;
+       }
 
        mutex_lock(&ctrl->subsys->lock);
        head = nvme_find_ns_head(ctrl->subsys, nsid);
        if (!head) {
+               ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, ids);
+               if (ret) {
+                       dev_err(ctrl->device,
+                               "duplicate IDs in subsystem for nsid %d\n",
+                               nsid);
+                       goto out_unlock;
+               }
                head = nvme_alloc_ns_head(ctrl, nsid, ids);
                if (IS_ERR(head)) {
                        ret = PTR_ERR(head);
@@ -3860,13 +3943,27 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
                goto out_cleanup_disk;
 
        /*
-        * Without the multipath code enabled, multiple controller per
-        * subsystems are visible as devices and thus we cannot use the
-        * subsystem instance.
+        * If multipathing is enabled, the device name for all disks and not
+        * just those that represent shared namespaces needs to be based on the
+        * subsystem instance.  Using the controller instance for private
+        * namespaces could lead to naming collisions between shared and private
+        * namespaces if they don't use a common numbering scheme.
+        *
+        * If multipathing is not enabled, disk names must use the controller
+        * instance as shared namespaces will show up as multiple block
+        * devices.
         */
-       if (!nvme_mpath_set_disk_name(ns, disk->disk_name, &disk->flags))
+       if (ns->head->disk) {
+               sprintf(disk->disk_name, "nvme%dc%dn%d", ctrl->subsys->instance,
+                       ctrl->instance, ns->head->instance);
+               disk->flags |= GENHD_FL_HIDDEN;
+       } else if (multipath) {
+               sprintf(disk->disk_name, "nvme%dn%d", ctrl->subsys->instance,
+                       ns->head->instance);
+       } else {
                sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance,
                        ns->head->instance);
+       }
 
        if (nvme_update_ns_info(ns, id))
                goto out_unlink_ns;
@@ -4231,6 +4328,13 @@ static int nvme_class_uevent(struct device *dev, struct kobj_uevent_env *env)
        return ret;
 }
 
+static void nvme_change_uevent(struct nvme_ctrl *ctrl, char *envdata)
+{
+       char *envp[2] = { envdata, NULL };
+
+       kobject_uevent_env(&ctrl->device->kobj, KOBJ_CHANGE, envp);
+}
+
 static void nvme_aen_uevent(struct nvme_ctrl *ctrl)
 {
        char *envp[2] = { NULL, NULL };
@@ -4398,6 +4502,8 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl)
                nvme_queue_scan(ctrl);
                nvme_start_queues(ctrl);
        }
+
+       nvme_change_uevent(ctrl, "NVME_EVENT=connected");
 }
 EXPORT_SYMBOL_GPL(nvme_start_ctrl);
 
@@ -4431,7 +4537,7 @@ static void nvme_free_ctrl(struct device *dev)
        struct nvme_subsystem *subsys = ctrl->subsys;
 
        if (!subsys || ctrl->instance != subsys->instance)
-               ida_simple_remove(&nvme_instance_ida, ctrl->instance);
+               ida_free(&nvme_instance_ida, ctrl->instance);
 
        nvme_free_cels(ctrl);
        nvme_mpath_uninit(ctrl);
@@ -4490,7 +4596,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
                goto out;
        }
 
-       ret = ida_simple_get(&nvme_instance_ida, 0, 0, GFP_KERNEL);
+       ret = ida_alloc(&nvme_instance_ida, GFP_KERNEL);
        if (ret < 0)
                goto out;
        ctrl->instance = ret;
@@ -4531,7 +4637,7 @@ out_free_name:
        nvme_put_ctrl(ctrl);
        kfree_const(ctrl->device->kobj.name);
 out_release_instance:
-       ida_simple_remove(&nvme_instance_ida, ctrl->instance);
+       ida_free(&nvme_instance_ida, ctrl->instance);
 out:
        if (ctrl->discard_page)
                __free_page(ctrl->discard_page);