nvme: refactor namespaces to support non-gendisk devices
[linux-2.6-microblaze.git] / drivers / nvme / host / core.c
index 2feacc7..2c3da33 100644 (file)
@@ -888,42 +888,33 @@ 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)) {
+       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);
-               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 +953,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;
 }
 
@@ -1642,6 +1651,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,33 +1670,54 @@ 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_disk(ns->disk))
-               goto out_free_disk;
+       if (nvme_revalidate_ns(ns, &id))
+               goto out_free_queue;
+
+       if (nvme_nvm_ns_supported(ns, id)) {
+               if (nvme_nvm_register(ns->queue, disk_name)) {
+                       dev_warn(ctrl->dev,
+                               "%s: LightNVM init failure\n", __func__);
+                       goto out_free_id;
+               }
+
+               disk = alloc_disk_node(0, node);
+               if (!disk)
+                       goto out_free_id;
+               memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
+               ns->disk = disk;
+               ns->type = NVME_NS_LIGHTNVM;
+       } 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);
+
+       kfree(id);
+
        if (ns->type == NVME_NS_LIGHTNVM)
                return;
 
@@ -1695,8 +1727,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: