NVMe: Fix error clean-up on nvme_alloc_queue
[linux-2.6-block.git] / drivers / block / nvme-core.c
index a89f7dbefba015bf08036bfc335b1de3b25e01b8..388c54d84809f57f650953834378e3b3ff4df6e3 100644 (file)
@@ -477,7 +477,7 @@ static int nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns,
 
        range->cattr = cpu_to_le32(0);
        range->nlb = cpu_to_le32(bio->bi_size >> ns->lba_shift);
-       range->slba = cpu_to_le64(bio->bi_sector >> (ns->lba_shift - 9));
+       range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector));
 
        memset(cmnd, 0, sizeof(*cmnd));
        cmnd->dsm.opcode = nvme_cmd_dsm;
@@ -590,7 +590,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
        cmnd->rw.nsid = cpu_to_le32(ns->ns_id);
        length = nvme_setup_prps(nvmeq->dev, &cmnd->common, iod, length,
                                                                GFP_ATOMIC);
-       cmnd->rw.slba = cpu_to_le64(bio->bi_sector >> (ns->lba_shift - 9));
+       cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector));
        cmnd->rw.length = cpu_to_le16((length >> ns->lba_shift) - 1);
        cmnd->rw.control = cpu_to_le16(control);
        cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
@@ -875,7 +875,7 @@ static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout)
                void *ctx;
                nvme_completion_fn fn;
                static struct nvme_completion cqe = {
-                       .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1,
+                       .status = cpu_to_le16(NVME_SC_ABORT_REQ << 1),
                };
 
                if (timeout && !time_after(now, info[cmdid].timeout))
@@ -956,7 +956,7 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
        return nvmeq;
 
  free_cqdma:
-       dma_free_coherent(dmadev, CQ_SIZE(nvmeq->q_depth), (void *)nvmeq->cqes,
+       dma_free_coherent(dmadev, CQ_SIZE(depth), (void *)nvmeq->cqes,
                                                        nvmeq->cq_dma_addr);
  free_nvmeq:
        kfree(nvmeq);
@@ -1054,14 +1054,19 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
                }
        }
 
-       if (result) {
-               nvme_free_queue_mem(nvmeq);
-               return result;
-       }
+       if (result)
+               goto free_q;
 
        result = queue_request_irq(dev, nvmeq, "nvme admin");
+       if (result)
+               goto free_q;
+
        dev->queues[0] = nvmeq;
        return result;
+
+ free_q:
+       nvme_free_queue_mem(nvmeq);
+       return result;
 }
 
 struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
@@ -1166,10 +1171,10 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        c.rw.slba = cpu_to_le64(io.slba);
        c.rw.length = cpu_to_le16(io.nblocks);
        c.rw.control = cpu_to_le16(io.control);
-       c.rw.dsmgmt = cpu_to_le16(io.dsmgmt);
-       c.rw.reftag = io.reftag;
-       c.rw.apptag = io.apptag;
-       c.rw.appmask = io.appmask;
+       c.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
+       c.rw.reftag = cpu_to_le32(io.reftag);
+       c.rw.apptag = cpu_to_le16(io.apptag);
+       c.rw.appmask = cpu_to_le16(io.appmask);
        /* XXX: metadata */
        length = nvme_setup_prps(dev, &c.common, iod, length, GFP_KERNEL);
 
@@ -1291,7 +1296,7 @@ static int nvme_kthread(void *data)
        struct nvme_dev *dev;
 
        while (!kthread_should_stop()) {
-               __set_current_state(TASK_RUNNING);
+               set_current_state(TASK_INTERRUPTIBLE);
                spin_lock(&dev_list_lock);
                list_for_each_entry(dev, &dev_list, node) {
                        int i;
@@ -1308,8 +1313,7 @@ static int nvme_kthread(void *data)
                        }
                }
                spin_unlock(&dev_list_lock);
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ);
+               schedule_timeout(round_jiffies_relative(HZ));
        }
        return 0;
 }
@@ -1502,6 +1506,12 @@ static void nvme_free_queues(struct nvme_dev *dev)
                nvme_free_queue(dev, i);
 }
 
+/*
+ * Return: error value if an error occurred setting up the queues or calling
+ * Identify Device.  0 if these succeeded, even if adding some of the
+ * namespaces failed.  At the moment, these failures are silent.  TBD which
+ * failures should be reported.
+ */
 static int nvme_dev_add(struct nvme_dev *dev)
 {
        int res, nn, i;
@@ -1555,7 +1565,7 @@ static int nvme_dev_add(struct nvme_dev *dev)
        }
        list_for_each_entry(ns, &dev->namespaces, list)
                add_disk(ns->disk);
-
+       res = 0;
        goto out;
 
  out_free:
@@ -1641,6 +1651,56 @@ static void nvme_release_instance(struct nvme_dev *dev)
        spin_unlock(&dev_list_lock);
 }
 
+static void nvme_free_dev(struct kref *kref)
+{
+       struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
+       nvme_dev_remove(dev);
+       pci_disable_msix(dev->pci_dev);
+       iounmap(dev->bar);
+       nvme_release_instance(dev);
+       nvme_release_prp_pools(dev);
+       pci_disable_device(dev->pci_dev);
+       pci_release_regions(dev->pci_dev);
+       kfree(dev->queues);
+       kfree(dev->entry);
+       kfree(dev);
+}
+
+static int nvme_dev_open(struct inode *inode, struct file *f)
+{
+       struct nvme_dev *dev = container_of(f->private_data, struct nvme_dev,
+                                                               miscdev);
+       kref_get(&dev->kref);
+       f->private_data = dev;
+       return 0;
+}
+
+static int nvme_dev_release(struct inode *inode, struct file *f)
+{
+       struct nvme_dev *dev = f->private_data;
+       kref_put(&dev->kref, nvme_free_dev);
+       return 0;
+}
+
+static long nvme_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+       struct nvme_dev *dev = f->private_data;
+       switch (cmd) {
+       case NVME_IOCTL_ADMIN_CMD:
+               return nvme_user_admin_cmd(dev, (void __user *)arg);
+       default:
+               return -ENOTTY;
+       }
+}
+
+static const struct file_operations nvme_dev_fops = {
+       .owner          = THIS_MODULE,
+       .open           = nvme_dev_open,
+       .release        = nvme_dev_release,
+       .unlocked_ioctl = nvme_dev_ioctl,
+       .compat_ioctl   = nvme_dev_ioctl,
+};
+
 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int bars, result = -ENOMEM;
@@ -1699,8 +1759,20 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (result)
                goto delete;
 
+       scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance);
+       dev->miscdev.minor = MISC_DYNAMIC_MINOR;
+       dev->miscdev.parent = &pdev->dev;
+       dev->miscdev.name = dev->name;
+       dev->miscdev.fops = &nvme_dev_fops;
+       result = misc_register(&dev->miscdev);
+       if (result)
+               goto remove;
+
+       kref_init(&dev->kref);
        return 0;
 
+ remove:
+       nvme_dev_remove(dev);
  delete:
        spin_lock(&dev_list_lock);
        list_del(&dev->node);
@@ -1726,16 +1798,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 static void nvme_remove(struct pci_dev *pdev)
 {
        struct nvme_dev *dev = pci_get_drvdata(pdev);
-       nvme_dev_remove(dev);
-       pci_disable_msix(pdev);
-       iounmap(dev->bar);
-       nvme_release_instance(dev);
-       nvme_release_prp_pools(dev);
-       pci_disable_device(pdev);
-       pci_release_regions(pdev);
-       kfree(dev->queues);
-       kfree(dev->entry);
-       kfree(dev);
+       misc_deregister(&dev->miscdev);
+       kref_put(&dev->kref, nvme_free_dev);
 }
 
 /* These functions are yet to be implemented */