Merge branch 'for-4.9/block-irq' of git://git.kernel.dk/linux-block
[cascardo/linux.git] / drivers / nvme / host / core.c
index b245616..329381a 100644 (file)
@@ -156,12 +156,14 @@ static void nvme_free_ns(struct kref *kref)
 {
        struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
 
-       if (ns->type == NVME_NS_LIGHTNVM)
-               nvme_nvm_unregister(ns->queue, ns->disk->disk_name);
+       if (ns->ndev)
+               nvme_nvm_unregister(ns);
 
-       spin_lock(&dev_list_lock);
-       ns->disk->private_data = NULL;
-       spin_unlock(&dev_list_lock);
+       if (ns->disk) {
+               spin_lock(&dev_list_lock);
+               ns->disk->private_data = NULL;
+               spin_unlock(&dev_list_lock);
+       }
 
        put_disk(ns->disk);
        ida_simple_remove(&ns->ctrl->ns_ida, ns->instance);
@@ -597,7 +599,7 @@ int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
 }
 
 int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
-                                       dma_addr_t dma_addr, u32 *result)
+                     void *buffer, size_t buflen, u32 *result)
 {
        struct nvme_command c;
        struct nvme_completion cqe;
@@ -606,10 +608,9 @@ 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.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,
+       ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, buffer, buflen, 0,
                        NVME_QID_ANY, 0, 0);
        if (ret >= 0 && result)
                *result = le32_to_cpu(cqe.result);
@@ -617,7 +618,7 @@ int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
 }
 
 int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
-                                       dma_addr_t dma_addr, u32 *result)
+                     void *buffer, size_t buflen, u32 *result)
 {
        struct nvme_command c;
        struct nvme_completion cqe;
@@ -625,12 +626,11 @@ 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.dptr.prp1 = cpu_to_le64(dma_addr);
        c.features.fid = cpu_to_le32(fid);
        c.features.dword11 = cpu_to_le32(dword11);
 
-       ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, NULL, 0, 0,
-                       NVME_QID_ANY, 0, 0);
+       ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe,
+                       buffer, buflen, 0, NVME_QID_ANY, 0, 0);
        if (ret >= 0 && result)
                *result = le32_to_cpu(cqe.result);
        return ret;
@@ -664,7 +664,7 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
        u32 result;
        int status, nr_io_queues;
 
-       status = nvme_set_features(ctrl, NVME_FEAT_NUM_QUEUES, q_count, 0,
+       status = nvme_set_features(ctrl, NVME_FEAT_NUM_QUEUES, q_count, NULL, 0,
                        &result);
        if (status < 0)
                return status;
@@ -888,42 +888,32 @@ static void nvme_config_discard(struct nvme_ns *ns)
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
 }
 
-static int nvme_revalidate_disk(struct gendisk *disk)
+static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id)
 {
-       struct nvme_ns *ns = disk->private_data;
-       struct nvme_id_ns *id;
-       u8 lbaf, pi_type;
-       u16 old_ms;
-       unsigned short bs;
-
-       if (test_bit(NVME_NS_DEAD, &ns->flags)) {
-               set_capacity(disk, 0);
-               return -ENODEV;
-       }
-       if (nvme_identify_ns(ns->ctrl, ns->ns_id, &id)) {
-               dev_warn(disk_to_dev(ns->disk), "%s: Identify failure\n",
-                               __func__);
-               return -ENODEV;
-       }
-       if (id->ncap == 0) {
-               kfree(id);
+       if (nvme_identify_ns(ns->ctrl, ns->ns_id, id)) {
+               dev_warn(ns->ctrl->dev, "%s: Identify failure\n", __func__);
                return -ENODEV;
        }
 
-       if (nvme_nvm_ns_supported(ns, id) && ns->type != NVME_NS_LIGHTNVM) {
-               if (nvme_nvm_register(ns->queue, disk->disk_name)) {
-                       dev_warn(disk_to_dev(ns->disk),
-                               "%s: LightNVM init failure\n", __func__);
-                       kfree(id);
-                       return -ENODEV;
-               }
-               ns->type = NVME_NS_LIGHTNVM;
+       if ((*id)->ncap == 0) {
+               kfree(*id);
+               return -ENODEV;
        }
 
        if (ns->ctrl->vs >= NVME_VS(1, 1))
-               memcpy(ns->eui, id->eui64, sizeof(ns->eui));
+               memcpy(ns->eui, (*id)->eui64, sizeof(ns->eui));
        if (ns->ctrl->vs >= NVME_VS(1, 2))
-               memcpy(ns->uuid, id->nguid, sizeof(ns->uuid));
+               memcpy(ns->uuid, (*id)->nguid, sizeof(ns->uuid));
+
+       return 0;
+}
+
+static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
+{
+       struct nvme_ns *ns = disk->private_data;
+       u8 lbaf, pi_type;
+       u16 old_ms;
+       unsigned short bs;
 
        old_ms = ns->ms;
        lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
@@ -962,8 +952,26 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        if (ns->ctrl->oncs & NVME_CTRL_ONCS_DSM)
                nvme_config_discard(ns);
        blk_mq_unfreeze_queue(disk->queue);
+}
+
+static int nvme_revalidate_disk(struct gendisk *disk)
+{
+       struct nvme_ns *ns = disk->private_data;
+       struct nvme_id_ns *id = NULL;
+       int ret;
+
+       if (test_bit(NVME_NS_DEAD, &ns->flags)) {
+               set_capacity(disk, 0);
+               return -ENODEV;
+       }
+
+       ret = nvme_revalidate_ns(ns, &id);
+       if (ret)
+               return ret;
 
+       __nvme_revalidate_disk(disk, id);
        kfree(id);
+
        return 0;
 }
 
@@ -1425,7 +1433,7 @@ static DEVICE_ATTR(rescan_controller, S_IWUSR, NULL, nvme_sysfs_rescan);
 static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
                                                                char *buf)
 {
-       struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+       struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
        struct nvme_ctrl *ctrl = ns->ctrl;
        int serial_len = sizeof(ctrl->serial);
        int model_len = sizeof(ctrl->model);
@@ -1449,7 +1457,7 @@ static DEVICE_ATTR(wwid, S_IRUGO, wwid_show, NULL);
 static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
                                                                char *buf)
 {
-       struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+       struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
        return sprintf(buf, "%pU\n", ns->uuid);
 }
 static DEVICE_ATTR(uuid, S_IRUGO, uuid_show, NULL);
@@ -1457,7 +1465,7 @@ static DEVICE_ATTR(uuid, S_IRUGO, uuid_show, NULL);
 static ssize_t eui_show(struct device *dev, struct device_attribute *attr,
                                                                char *buf)
 {
-       struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+       struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
        return sprintf(buf, "%8phd\n", ns->eui);
 }
 static DEVICE_ATTR(eui, S_IRUGO, eui_show, NULL);
@@ -1465,7 +1473,7 @@ static DEVICE_ATTR(eui, S_IRUGO, eui_show, NULL);
 static ssize_t nsid_show(struct device *dev, struct device_attribute *attr,
                                                                char *buf)
 {
-       struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+       struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
        return sprintf(buf, "%d\n", ns->ns_id);
 }
 static DEVICE_ATTR(nsid, S_IRUGO, nsid_show, NULL);
@@ -1482,7 +1490,7 @@ static umode_t nvme_ns_attrs_are_visible(struct kobject *kobj,
                struct attribute *a, int n)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
-       struct nvme_ns *ns = dev_to_disk(dev)->private_data;
+       struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
 
        if (a == &dev_attr_uuid.attr) {
                if (!memchr_inv(ns->uuid, 0, sizeof(ns->uuid)))
@@ -1642,6 +1650,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
 {
        struct nvme_ns *ns;
        struct gendisk *disk;
+       struct nvme_id_ns *id;
+       char disk_name[DISK_NAME_LEN];
        int node = dev_to_node(ctrl->dev);
 
        ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
@@ -1659,34 +1669,49 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        ns->queue->queuedata = ns;
        ns->ctrl = ctrl;
 
-       disk = alloc_disk_node(0, node);
-       if (!disk)
-               goto out_free_queue;
-
        kref_init(&ns->kref);
        ns->ns_id = nsid;
-       ns->disk = disk;
        ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
 
-
        blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
        nvme_set_queue_limits(ctrl, ns->queue);
 
-       disk->fops = &nvme_fops;
-       disk->private_data = ns;
-       disk->queue = ns->queue;
-       disk->flags = GENHD_FL_EXT_DEVT;
-       sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
+       sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
+
+       if (nvme_revalidate_ns(ns, &id))
+               goto out_free_queue;
 
-       if (nvme_revalidate_disk(ns->disk))
-               goto out_free_disk;
+       if (nvme_nvm_ns_supported(ns, id)) {
+               if (nvme_nvm_register(ns, disk_name, node,
+                                                       &nvme_ns_attr_group)) {
+                       dev_warn(ctrl->dev, "%s: LightNVM init failure\n",
+                                                               __func__);
+                       goto out_free_id;
+               }
+       } else {
+               disk = alloc_disk_node(0, node);
+               if (!disk)
+                       goto out_free_id;
+
+               disk->fops = &nvme_fops;
+               disk->private_data = ns;
+               disk->queue = ns->queue;
+               disk->flags = GENHD_FL_EXT_DEVT;
+               memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
+               ns->disk = disk;
+
+               __nvme_revalidate_disk(disk, id);
+       }
 
        mutex_lock(&ctrl->namespaces_mutex);
        list_add_tail(&ns->list, &ctrl->namespaces);
        mutex_unlock(&ctrl->namespaces_mutex);
 
        kref_get(&ctrl->kref);
-       if (ns->type == NVME_NS_LIGHTNVM)
+
+       kfree(id);
+
+       if (ns->ndev)
                return;
 
        device_add_disk(ctrl->device, ns->disk);
@@ -1695,8 +1720,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
                pr_warn("%s: failed to create sysfs group for identification\n",
                        ns->disk->disk_name);
        return;
- out_free_disk:
-       kfree(disk);
+ out_free_id:
+       kfree(id);
  out_free_queue:
        blk_cleanup_queue(ns->queue);
  out_release_instance:
@@ -1710,7 +1735,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
        if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
                return;
 
-       if (ns->disk->flags & GENHD_FL_UP) {
+       if (ns->disk && ns->disk->flags & GENHD_FL_UP) {
                if (blk_get_integrity(ns->disk))
                        blk_integrity_unregister(ns->disk);
                sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
@@ -1733,7 +1758,7 @@ static void nvme_validate_ns(struct nvme_ctrl *ctrl, unsigned nsid)
 
        ns = nvme_find_get_ns(ctrl, nsid);
        if (ns) {
-               if (revalidate_disk(ns->disk))
+               if (ns->disk && revalidate_disk(ns->disk))
                        nvme_ns_remove(ns);
                nvme_put_ns(ns);
        } else
@@ -2035,7 +2060,7 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
                 * Revalidating a dead namespace sets capacity to 0. This will
                 * end buffered writers dirtying pages that can't be synced.
                 */
-               if (!test_and_set_bit(NVME_NS_DEAD, &ns->flags))
+               if (ns->disk && !test_and_set_bit(NVME_NS_DEAD, &ns->flags))
                        revalidate_disk(ns->disk);
 
                blk_set_queue_dying(ns->queue);