Merge branch 'for-4.4/reservations' of git://git.kernel.dk/linux-block
[firefly-linux-kernel-4.4.55.git] / drivers / nvme / host / pci.c
index 9a12d5a325551b6e1217bf788fc640e3bd2b8918..e878590e71b68ad3863ddc83006e76420996a4f4 100644 (file)
@@ -540,7 +540,7 @@ static void nvme_dif_remap(struct request *req,
        virt = bip_get_seed(bip);
        phys = nvme_block_nr(ns, blk_rq_pos(req));
        nlb = (blk_rq_bytes(req) >> ns->lba_shift);
-       ts = ns->disk->integrity->tuple_size;
+       ts = ns->disk->queue->integrity.tuple_size;
 
        for (i = 0; i < nlb; i++, virt++, phys++) {
                pi = (struct t10_pi_tuple *)p;
@@ -550,36 +550,20 @@ static void nvme_dif_remap(struct request *req,
        kunmap_atomic(pmap);
 }
 
-static int nvme_noop_verify(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-static int nvme_noop_generate(struct blk_integrity_iter *iter)
-{
-       return 0;
-}
-
-struct blk_integrity nvme_meta_noop = {
-       .name                   = "NVME_META_NOOP",
-       .generate_fn            = nvme_noop_generate,
-       .verify_fn              = nvme_noop_verify,
-};
-
 static void nvme_init_integrity(struct nvme_ns *ns)
 {
        struct blk_integrity integrity;
 
        switch (ns->pi_type) {
        case NVME_NS_DPS_PI_TYPE3:
-               integrity = t10_pi_type3_crc;
+               integrity.profile = &t10_pi_type3_crc;
                break;
        case NVME_NS_DPS_PI_TYPE1:
        case NVME_NS_DPS_PI_TYPE2:
-               integrity = t10_pi_type1_crc;
+               integrity.profile = &t10_pi_type1_crc;
                break;
        default:
-               integrity = nvme_meta_noop;
+               integrity.profile = NULL;
                break;
        }
        integrity.tuple_size = ns->ms;
@@ -609,6 +593,7 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
        struct request *req = iod_get_private(iod);
        struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
        u16 status = le16_to_cpup(&cqe->status) >> 1;
+       bool requeue = false;
        int error = 0;
 
        if (unlikely(status)) {
@@ -616,12 +601,13 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
                    && (jiffies - req->start_time) < req->timeout) {
                        unsigned long flags;
 
+                       requeue = true;
                        blk_mq_requeue_request(req);
                        spin_lock_irqsave(req->q->queue_lock, flags);
                        if (!blk_queue_stopped(req->q))
                                blk_mq_kick_requeue_list(req->q);
                        spin_unlock_irqrestore(req->q->queue_lock, flags);
-                       return;
+                       goto release_iod;
                }
 
                if (req->cmd_type == REQ_TYPE_DRV_PRIV) {
@@ -644,6 +630,7 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
                        "completing aborted command with status:%04x\n",
                        error);
 
+release_iod:
        if (iod->nents) {
                dma_unmap_sg(nvmeq->dev->dev, iod->sg, iod->nents,
                        rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
@@ -656,7 +643,8 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
        }
        nvme_free_iod(nvmeq->dev, iod);
 
-       blk_mq_complete_request(req, error);
+       if (likely(!requeue))
+               blk_mq_complete_request(req, error);
 }
 
 /* length is in bytes.  gfp flags indicates whether we may sleep. */
@@ -1950,6 +1938,9 @@ 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);
+
        spin_lock(&dev_list_lock);
        ns->disk->private_data = NULL;
        spin_unlock(&dev_list_lock);
@@ -2019,6 +2010,16 @@ static int nvme_revalidate_disk(struct gendisk *disk)
                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(dev->dev,
+                               "%s: LightNVM init failure\n", __func__);
+                       kfree(id);
+                       return -ENODEV;
+               }
+               ns->type = NVME_NS_LIGHTNVM;
+       }
+
        old_ms = ns->ms;
        lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
        ns->lba_shift = id->lbaf[lbaf].ds;
@@ -2037,6 +2038,7 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
                                        id->dps & NVME_NS_DPS_PI_MASK : 0;
 
+       blk_mq_freeze_queue(disk->queue);
        if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
                                ns->ms != old_ms ||
                                bs != queue_logical_block_size(disk->queue) ||
@@ -2046,17 +2048,19 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        ns->pi_type = pi_type;
        blk_queue_logical_block_size(ns->queue, bs);
 
-       if (ns->ms && !blk_get_integrity(disk) && (disk->flags & GENHD_FL_UP) &&
-                                                               !ns->ext)
+       if (ns->ms && !ns->ext)
                nvme_init_integrity(ns);
 
-       if (ns->ms && !(ns->ms == 8 && ns->pi_type) && !blk_get_integrity(disk))
+       if ((ns->ms && !(ns->ms == 8 && ns->pi_type) &&
+                                               !blk_get_integrity(disk)) ||
+                                               ns->type == NVME_NS_LIGHTNVM)
                set_capacity(disk, 0);
        else
                set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
 
        if (dev->oncs & NVME_CTRL_ONCS_DSM)
                nvme_config_discard(ns);
+       blk_mq_unfreeze_queue(disk->queue);
 
        kfree(id);
        return 0;
@@ -2266,17 +2270,19 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
                goto out_free_disk;
 
        kref_get(&dev->kref);
-       add_disk(ns->disk);
-       if (ns->ms) {
-               struct block_device *bd = bdget_disk(ns->disk, 0);
-               if (!bd)
-                       return;
-               if (blkdev_get(bd, FMODE_READ, NULL)) {
-                       bdput(bd);
-                       return;
+       if (ns->type != NVME_NS_LIGHTNVM) {
+               add_disk(ns->disk);
+               if (ns->ms) {
+                       struct block_device *bd = bdget_disk(ns->disk, 0);
+                       if (!bd)
+                               return;
+                       if (blkdev_get(bd, FMODE_READ, NULL)) {
+                               bdput(bd);
+                               return;
+                       }
+                       blkdev_reread_part(bd);
+                       blkdev_put(bd, FMODE_READ);
                }
-               blkdev_reread_part(bd);
-               blkdev_put(bd, FMODE_READ);
        }
        return;
  out_free_disk:
@@ -2503,11 +2509,8 @@ static void nvme_ns_remove(struct nvme_ns *ns)
 
        if (kill)
                blk_set_queue_dying(ns->queue);
-       if (ns->disk->flags & GENHD_FL_UP) {
-               if (blk_get_integrity(ns->disk))
-                       blk_integrity_unregister(ns->disk);
+       if (ns->disk->flags & GENHD_FL_UP)
                del_gendisk(ns->disk);
-       }
        if (kill || !blk_queue_dying(ns->queue)) {
                blk_mq_abort_requeue_list(ns->queue);
                blk_cleanup_queue(ns->queue);