--- /dev/null
+From: Vladimir Sokolovsky <vlad@mellanox.com>
+Subject: [PATCH] BACKPORT: nvme host
+
+Signed-off-by: Vladimir Sokolovsky <vlad@mellanox.com>
+---
+ block/blk-mq-rdma.c | 4 +
+ drivers/nvme/host/core.c | 346 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/nvme/host/fabrics.c | 39 +++++
+ drivers/nvme/host/fc.c | 95 ++++++++++++
+ drivers/nvme/host/lightnvm.c | 6 +
+ drivers/nvme/host/nvme.h | 78 +++++++++-
+ drivers/nvme/host/pci.c | 317 ++++++++++++++++++++++++++++++++++++++-
+ drivers/nvme/host/rdma.c | 156 +++++++++++++++++++
+ include/linux/blk-mq-rdma.h | 5 +
+ 9 files changed, 1044 insertions(+), 2 deletions(-)
+
+diff --git a/block/blk-mq-rdma.c b/block/blk-mq-rdma.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/block/blk-mq-rdma.c
++++ b/block/blk-mq-rdma.c
+@@ -1,3 +1,5 @@
++#ifdef HAVE_BLK_MQ_MAP_QUEUES
++
+ /*
+ * Copyright (c) 2017 Sagi Grimberg.
+ *
+@@ -50,3 +52,5 @@ fallback:
+ return blk_mq_map_queues(set);
+ }
+ EXPORT_SYMBOL_GPL(blk_mq_rdma_map_queues);
++
++#endif /* HAVE_BLK_MQ_MAP_QUEUES */
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -22,11 +22,15 @@
+ #include <linux/list_sort.h>
+ #include <linux/slab.h>
+ #include <linux/types.h>
++#ifdef HAVE_PR_H
+ #include <linux/pr.h>
++#endif
+ #include <linux/ptrace.h>
+ #include <linux/nvme_ioctl.h>
+ #include <linux/t10-pi.h>
++#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
+ #include <linux/pm_qos.h>
++#endif
+ #include <asm/unaligned.h>
+
+ #define CREATE_TRACE_POINTS
+@@ -55,18 +59,22 @@ static u8 nvme_max_retries = 5;
+ module_param_named(max_retries, nvme_max_retries, byte, 0644);
+ MODULE_PARM_DESC(max_retries, "max number of retries a command may have");
+
++#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
+ static unsigned long default_ps_max_latency_us = 100000;
+ module_param(default_ps_max_latency_us, ulong, 0644);
+ MODULE_PARM_DESC(default_ps_max_latency_us,
+ "max power saving latency for new devices; use PM QOS to change per device");
++#endif
+
+ static bool force_apst;
+ module_param(force_apst, bool, 0644);
+ MODULE_PARM_DESC(force_apst, "allow APST for newly enumerated devices even if quirked off");
+
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ static bool streams;
+ module_param(streams, bool, 0644);
+ MODULE_PARM_DESC(streams, "turn on support for Streams write directives");
++#endif
+
+ /*
+ * nvme_wq - hosts nvme related works that are not reset or delete
+@@ -205,7 +213,11 @@ static blk_status_t nvme_error_status(struct request *req)
+ case NVME_SC_RESERVATION_CONFLICT:
+ return BLK_STS_NEXUS;
+ default:
++#ifdef HAVE_BLK_MQ_END_REQUEST_TAKES_BLK_STATUS_T
+ return BLK_STS_IOERR;
++#else
++ return -EIO;
++#endif
+ }
+ }
+
+@@ -234,7 +246,12 @@ void nvme_complete_rq(struct request *req)
+
+ if (!blk_queue_dying(req->q)) {
+ nvme_req(req)->retries++;
++#ifdef HAVE_BLK_MQ_REQUEUE_REQUEST_2_PARAMS
+ blk_mq_requeue_request(req, true);
++#else
++ blk_mq_requeue_request(req);
++ blk_mq_kick_requeue_list(req->q);
++#endif
+ return;
+ }
+ }
+@@ -251,7 +268,11 @@ void nvme_cancel_request(struct request *req, void *data, bool reserved)
+ "Cancelling I/O %d", req->tag);
+
+ nvme_req(req)->status = NVME_SC_ABORT_REQ;
++#ifdef HAVE_BLK_MQ_COMPLETE_REQUEST_HAS_2_PARAMS
++ blk_mq_complete_request(req, 0);
++#else
+ blk_mq_complete_request(req);
++#endif
+
+ }
+ EXPORT_SYMBOL_GPL(nvme_cancel_request);
+@@ -343,6 +364,18 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
+ }
+ EXPORT_SYMBOL_GPL(nvme_change_ctrl_state);
+
++#ifndef HAVE_CLEANUP_SRCU_STRUCT_QUIESCED
++static void nvme_free_ns_head_work(struct work_struct *work)
++{
++ struct nvme_ns_head *head =
++ container_of(work, struct nvme_ns_head, free_work);
++
++ cleanup_srcu_struct(&head->srcu);
++ nvme_put_subsystem(head->subsys);
++ kfree(head);
++}
++#endif
++
+ static void nvme_free_ns_head(struct kref *ref)
+ {
+ struct nvme_ns_head *head =
+@@ -351,9 +384,13 @@ static void nvme_free_ns_head(struct kref *ref)
+ nvme_mpath_remove_disk(head);
+ ida_simple_remove(&head->subsys->ns_ida, head->instance);
+ list_del_init(&head->entry);
++#ifdef HAVE_CLEANUP_SRCU_STRUCT_QUIESCED
+ cleanup_srcu_struct(&head->srcu);
+ nvme_put_subsystem(head->subsys);
+ kfree(head);
++#else
++ queue_work(system_wq, &head->free_work);
++#endif
+ }
+
+ static void nvme_put_ns_head(struct nvme_ns_head *head)
+@@ -381,28 +418,69 @@ static void nvme_put_ns(struct nvme_ns *ns)
+
+ static inline void nvme_clear_nvme_request(struct request *req)
+ {
++#ifdef HAVE_REQUEST_RQ_FLAGS
+ if (!(req->rq_flags & RQF_DONTPREP)) {
+ nvme_req(req)->retries = 0;
+ nvme_req(req)->flags = 0;
+ req->rq_flags |= RQF_DONTPREP;
+ }
++#else
++ if (!(req->cmd_flags & REQ_DONTPREP)) {
++ nvme_req(req)->retries = 0;
++ nvme_req(req)->flags = 0;
++ req->cmd_flags |= REQ_DONTPREP;
++ }
++#endif
+ }
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ struct request *nvme_alloc_request(struct request_queue *q,
+ struct nvme_command *cmd, blk_mq_req_flags_t flags, int qid)
++#else
++struct request *nvme_alloc_request(struct request_queue *q,
++ struct nvme_command *cmd, gfp_t gfp, bool reserved, int qid)
++#endif
+ {
++#ifdef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
+ unsigned op = nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
++#endif
+ struct request *req;
+
+ if (qid == NVME_QID_ANY) {
++#ifdef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
+ req = blk_mq_alloc_request(q, op, flags);
++#else
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
++ req = blk_mq_alloc_request(q, nvme_is_write(cmd), flags);
++#else
++ req = blk_mq_alloc_request(q, nvme_is_write(cmd), gfp, reserved);
++#endif /* HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS */
++#endif
+ } else {
++#ifdef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
+ req = blk_mq_alloc_request_hctx(q, op, flags,
+ qid ? qid - 1 : 0);
++#else
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
++ req = blk_mq_alloc_request_hctx(q, nvme_is_write(cmd), flags,
++ qid ? qid - 1 : 0);
++#else
++ // XXX We should call blk_mq_alloc_request_hctx() here.
++ req = blk_mq_alloc_request(q, nvme_is_write(cmd), gfp, reserved);
++#endif /* HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS */
++#endif
+ }
+ if (IS_ERR(req))
+ return req;
+
++#ifndef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
++#ifdef HAVE_BLKDEV_REQ_TYPE_DRV_PRIV
++ req->cmd_type = REQ_TYPE_DRV_PRIV;
++#else
++ req->cmd_type = REQ_TYPE_SPECIAL;
++#endif
++#endif
++
+ req->cmd_flags |= REQ_FAILFAST_DRIVER;
+ nvme_clear_nvme_request(req);
+ nvme_req(req)->cmd = cmd;
+@@ -411,6 +489,7 @@ struct request *nvme_alloc_request(struct request_queue *q,
+ }
+ EXPORT_SYMBOL_GPL(nvme_alloc_request);
+
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ static int nvme_toggle_streams(struct nvme_ctrl *ctrl, bool enable)
+ {
+ struct nvme_command c;
+@@ -509,6 +588,7 @@ static void nvme_assign_write_stream(struct nvme_ctrl *ctrl,
+ if (streamid < ARRAY_SIZE(req->q->write_hints))
+ req->q->write_hints[streamid] += blk_rq_bytes(req) >> 9;
+ }
++#endif /* HAVE_BLK_MAX_WRITE_HINTS */
+
+ static inline void nvme_setup_flush(struct nvme_ns *ns,
+ struct nvme_command *cmnd)
+@@ -521,14 +601,29 @@ static inline void nvme_setup_flush(struct nvme_ns *ns,
+ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
+ struct nvme_command *cmnd)
+ {
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ unsigned short segments = blk_rq_nr_discard_segments(req), n = 0;
++#endif
+ struct nvme_dsm_range *range;
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ struct bio *bio;
++#else
++ unsigned int nr_bytes = blk_rq_bytes(req);
++#endif
++#ifndef HAVE_REQUEST_RQ_FLAGS
++ struct page *page;
++ int offset;
++#endif
+
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC);
++#else
++ range = kmalloc(sizeof(*range), GFP_ATOMIC);
++#endif
+ if (!range)
+ return BLK_STS_RESOURCE;
+
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ __rq_for_each_bio(bio, req) {
+ u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector);
+ u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift;
+@@ -545,17 +640,49 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
+ kfree(range);
+ return BLK_STS_IOERR;
+ }
++#else
++ range->cattr = cpu_to_le32(0);
++ range->nlb = cpu_to_le32(nr_bytes >> ns->lba_shift);
++ range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
++#endif
+
+ memset(cmnd, 0, sizeof(*cmnd));
+ cmnd->dsm.opcode = nvme_cmd_dsm;
+ cmnd->dsm.nsid = cpu_to_le32(ns->head->ns_id);
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ cmnd->dsm.nr = cpu_to_le32(segments - 1);
++#else
++ cmnd->dsm.nr = 0;
++#endif
+ cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD);
+
++#ifndef HAVE_REQUEST_RQ_FLAGS
++ req->completion_data = range;
++ page = virt_to_page(range);
++ offset = offset_in_page(range);
++#ifdef HAVE_BLK_ADD_REQUEST_PAYLOAD_HAS_4_PARAMS
++ blk_add_request_payload(req, page, offset, sizeof(*range));
++#else
++ blk_add_request_payload(req, page, sizeof(*range));
++ req->bio->bi_io_vec->bv_offset = offset;
++#endif
++
++ /*
++ * we set __data_len back to the size of the area to be discarded
++ * on disk. This allows us to report completion on the full amount
++ * of blocks described by the request.
++ */
++ req->__data_len = nr_bytes;
++#else /* HAVE_REQUEST_RQ_FLAGS */
+ req->special_vec.bv_page = virt_to_page(range);
+ req->special_vec.bv_offset = offset_in_page(range);
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ req->special_vec.bv_len = sizeof(*range) * segments;
++#else
++ req->special_vec.bv_len = sizeof(*range);
++#endif
+ req->rq_flags |= RQF_SPECIAL_PAYLOAD;
++#endif /* HAVE_REQUEST_RQ_FLAGS */
+
+ return BLK_STS_OK;
+ }
+@@ -563,7 +690,9 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
+ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
+ struct request *req, struct nvme_command *cmnd)
+ {
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ struct nvme_ctrl *ctrl = ns->ctrl;
++#endif
+ u16 control = 0;
+ u32 dsmgmt = 0;
+
+@@ -581,8 +710,10 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
+ cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
+ cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
+
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ if (req_op(req) == REQ_OP_WRITE && ctrl->nr_streams)
+ nvme_assign_write_stream(ctrl, req, &control, &dsmgmt);
++#endif
+
+ if (ns->ms) {
+ /*
+@@ -623,6 +754,7 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
+
+ nvme_clear_nvme_request(req);
+
++#ifdef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
+ switch (req_op(req)) {
+ case REQ_OP_DRV_IN:
+ case REQ_OP_DRV_OUT:
+@@ -631,8 +763,10 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
+ case REQ_OP_FLUSH:
+ nvme_setup_flush(ns, cmd);
+ break;
++#ifdef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
+ case REQ_OP_WRITE_ZEROES:
+ /* currently only aliased to deallocate for a few ctrls: */
++#endif
+ case REQ_OP_DISCARD:
+ ret = nvme_setup_discard(ns, req, cmd);
+ break;
+@@ -644,6 +778,28 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
+ WARN_ON_ONCE(1);
+ return BLK_STS_IOERR;
+ }
++#else
++#ifdef HAVE_BLKDEV_REQ_TYPE_DRV_PRIV
++ if (req->cmd_type == REQ_TYPE_DRV_PRIV)
++#else
++ if (req->cmd_type == REQ_TYPE_SPECIAL)
++#endif
++ memcpy(cmd, nvme_req(req)->cmd, sizeof(*cmd));
++#ifdef HAVE_BLK_TYPES_REQ_OP_FLUSH
++ else if (req_op(req) == REQ_OP_FLUSH)
++#else
++ else if (req->cmd_flags & REQ_FLUSH)
++#endif
++ nvme_setup_flush(ns, cmd);
++#ifdef HAVE_BLK_TYPES_REQ_OP_DISCARD
++ else if (req_op(req) == REQ_OP_DISCARD)
++#else
++ else if (req->cmd_flags & REQ_DISCARD)
++#endif
++ ret = nvme_setup_discard(ns, req, cmd);
++ else
++ nvme_setup_rw(ns, req, cmd);
++#endif
+
+ cmd->common.command_id = req->tag;
+ if (ns)
+@@ -658,15 +814,25 @@ EXPORT_SYMBOL_GPL(nvme_setup_cmd);
+ * Returns 0 on success. If the result is negative, it's a Linux error code;
+ * if the result is positive, it's an NVM Express status code
+ */
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+ union nvme_result *result, void *buffer, unsigned bufflen,
+ unsigned timeout, int qid, int at_head,
+ blk_mq_req_flags_t flags)
++#else
++int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
++ union nvme_result *result, void *buffer, unsigned bufflen,
++ unsigned timeout, int qid, int at_head, gfp_t gfp, bool reserved)
++#endif
+ {
+ struct request *req;
+ int ret;
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ req = nvme_alloc_request(q, cmd, flags, qid);
++#else
++ req = nvme_alloc_request(q, cmd, gfp, reserved, qid);
++#endif
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+@@ -694,8 +860,13 @@ EXPORT_SYMBOL_GPL(__nvme_submit_sync_cmd);
+ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+ void *buffer, unsigned bufflen)
+ {
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ return __nvme_submit_sync_cmd(q, cmd, NULL, buffer, bufflen, 0,
+ NVME_QID_ANY, 0, 0);
++#else
++ return __nvme_submit_sync_cmd(q, cmd, NULL, buffer, bufflen, 0,
++ NVME_QID_ANY, 0, GFP_KERNEL, false);
++#endif
+ }
+ EXPORT_SYMBOL_GPL(nvme_submit_sync_cmd);
+
+@@ -720,8 +891,10 @@ static void *nvme_add_user_metadata(struct bio *bio, void __user *ubuf,
+ goto out_free_meta;
+ }
+
++#ifdef HAVE_BIO_INTEGRITY_PYLD_BIP_ITER
+ bip->bip_iter.bi_size = len;
+ bip->bip_iter.bi_sector = seed;
++#endif
+ ret = bio_integrity_add_page(bio, virt_to_page(buf), len,
+ offset_in_page(buf));
+ if (ret == len)
+@@ -746,7 +919,11 @@ static int nvme_submit_user_cmd(struct request_queue *q,
+ void *meta = NULL;
+ int ret;
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
++#else
++ req = nvme_alloc_request(q, cmd, GFP_KERNEL, false, NVME_QID_ANY);
++#endif
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+@@ -759,7 +936,17 @@ static int nvme_submit_user_cmd(struct request_queue *q,
+ if (ret)
+ goto out;
+ bio = req->bio;
++#ifdef HAVE_BIO_BI_DISK
+ bio->bi_disk = disk;
++#else
++ if (disk) {
++ bio->bi_bdev = bdget_disk(disk, 0);
++ if (!bio->bi_bdev) {
++ ret = -ENODEV;
++ goto out_unmap;
++ }
++ }
++#endif
+ if (disk && meta_buffer && meta_len) {
+ meta = nvme_add_user_metadata(bio, meta_buffer, meta_len,
+ meta_seed, write);
+@@ -767,7 +954,9 @@ static int nvme_submit_user_cmd(struct request_queue *q,
+ ret = PTR_ERR(meta);
+ goto out_unmap;
+ }
++#ifdef HAVE_BLK_TYPES_REQ_INTEGRITY
+ req->cmd_flags |= REQ_INTEGRITY;
++#endif
+ }
+ }
+
+@@ -784,8 +973,16 @@ static int nvme_submit_user_cmd(struct request_queue *q,
+ }
+ kfree(meta);
+ out_unmap:
++#ifdef HAVE_BIO_BI_DISK
+ if (bio)
+ blk_rq_unmap_user(bio);
++#else
++ if (bio) {
++ if (disk && bio->bi_bdev)
++ bdput(bio->bi_bdev);
++ blk_rq_unmap_user(bio);
++ }
++#endif
+ out:
+ blk_mq_free_request(req);
+ return ret;
+@@ -811,8 +1008,13 @@ static int nvme_keep_alive(struct nvme_ctrl *ctrl)
+ {
+ struct request *rq;
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd, BLK_MQ_REQ_RESERVED,
+ NVME_QID_ANY);
++#else
++ rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd, GFP_KERNEL, true,
++ NVME_QID_ANY);
++#endif
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+@@ -998,8 +1200,13 @@ static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword
+ c.features.fid = cpu_to_le32(fid);
+ c.features.dword11 = cpu_to_le32(dword11);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res,
+ buffer, buflen, 0, NVME_QID_ANY, 0, 0);
++#else
++ ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res,
++ buffer, buflen, 0, NVME_QID_ANY, 0, GFP_KERNEL, false);
++#endif
+ if (ret >= 0 && result)
+ *result = le32_to_cpu(res.u32);
+ return ret;
+@@ -1247,13 +1454,17 @@ static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned cmd, unsigned long arg)
+ case NVME_IOCTL_SUBMIT_IO:
+ return nvme_submit_io(ns, (void __user *)arg);
+ default:
++#ifdef HAVE_NVM_USER_VIO
+ #ifdef CONFIG_NVM
+ if (ns->ndev)
+ return nvme_nvm_ioctl(ns, cmd, arg);
+ #endif
++#endif
++#ifdef HAVE_LINUX_SED_OPAL_H
+ if (is_sed_ioctl(cmd))
+ return sed_ioctl(ns->ctrl->opal_dev, cmd,
+ (void __user *) arg);
++#endif
+ return -ENOTTY;
+ }
+ }
+@@ -1314,6 +1525,7 @@ static int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+ }
+
+ #ifdef CONFIG_BLK_DEV_INTEGRITY
++#ifdef HAVE_BLK_INTEGRITY_DEVICE_CAPABLE
+ static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type)
+ {
+ struct blk_integrity integrity;
+@@ -1342,6 +1554,19 @@ static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type)
+ #else
+ static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type)
+ {
++ struct blk_integrity integrity;
++
++ memset(&integrity, 0, sizeof(integrity));
++ integrity.tag_size = pi_type ? sizeof(u16) + sizeof(u32)
++ : sizeof(u16);
++ integrity.tuple_size = ms;
++ blk_integrity_register(disk, &integrity);
++ blk_queue_max_integrity_segments(disk->queue, 1);
++}
++#endif /* HAVE_BLK_INTEGRITY_DEVICE_CAPABLE */
++#else
++static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type)
++{
+ }
+ #endif /* CONFIG_BLK_DEV_INTEGRITY */
+
+@@ -1359,18 +1584,24 @@ static void nvme_config_discard(struct nvme_ctrl *ctrl,
+ if (stream_alignment)
+ size *= stream_alignment;
+
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) <
+ NVME_DSM_MAX_RANGES);
++#endif
+
+ queue->limits.discard_alignment = 0;
+ queue->limits.discard_granularity = size;
+
+ blk_queue_max_discard_sectors(queue, UINT_MAX);
++#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
+ blk_queue_max_discard_segments(queue, NVME_DSM_MAX_RANGES);
++#endif
+ blk_queue_flag_set(QUEUE_FLAG_DISCARD, queue);
+
++#ifdef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
+ if (ctrl->quirks & NVME_QUIRK_DEALLOCATE_ZEROES)
+ blk_queue_max_write_zeroes_sectors(queue, UINT_MAX);
++#endif
+ }
+
+ static void nvme_report_ns_ids(struct nvme_ctrl *ctrl, unsigned int nsid,
+@@ -1394,7 +1625,11 @@ static void nvme_report_ns_ids(struct nvme_ctrl *ctrl, unsigned int nsid,
+
+ static bool nvme_ns_ids_valid(struct nvme_ns_ids *ids)
+ {
++#ifdef HAVE_UUID_IS_NULL
+ return !uuid_is_null(&ids->uuid) ||
++#else
++ return false ||
++#endif
+ memchr_inv(ids->nguid, 0, sizeof(ids->nguid)) ||
+ memchr_inv(ids->eui64, 0, sizeof(ids->eui64));
+ }
+@@ -1413,8 +1648,10 @@ static void nvme_update_disk_info(struct gendisk *disk,
+ unsigned short bs = 1 << ns->lba_shift;
+ unsigned stream_alignment = 0;
+
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ if (ns->ctrl->nr_streams && ns->sws && ns->sgs)
+ stream_alignment = ns->sws * ns->sgs;
++#endif
+
+ blk_mq_freeze_queue(disk->queue);
+ blk_integrity_unregister(disk);
+@@ -1501,6 +1738,7 @@ out:
+ return ret;
+ }
+
++#ifdef HAVE_PR_H
+ static char nvme_pr_type(enum pr_type type)
+ {
+ switch (type) {
+@@ -1600,7 +1838,9 @@ static const struct pr_ops nvme_pr_ops = {
+ .pr_preempt = nvme_pr_preempt,
+ .pr_clear = nvme_pr_clear,
+ };
++#endif
+
++#ifdef HAVE_LINUX_SED_OPAL_H
+ #ifdef CONFIG_BLK_SED_OPAL
+ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
+ bool send)
+@@ -1617,11 +1857,17 @@ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
+ cmd.common.cdw10[0] = cpu_to_le32(((u32)secp) << 24 | ((u32)spsp) << 8);
+ cmd.common.cdw10[1] = cpu_to_le32(len);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len,
+ ADMIN_TIMEOUT, NVME_QID_ANY, 1, 0);
++#else
++ return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len,
++ ADMIN_TIMEOUT, NVME_QID_ANY, 1, GFP_KERNEL, false);
++#endif
+ }
+ EXPORT_SYMBOL_GPL(nvme_sec_submit);
+ #endif /* CONFIG_BLK_SED_OPAL */
++#endif /* HAVE_LINUX_SED_OPAL_H */
+
+ static const struct block_device_operations nvme_fops = {
+ .owner = THIS_MODULE,
+@@ -1631,7 +1877,9 @@ static const struct block_device_operations nvme_fops = {
+ .release = nvme_release,
+ .getgeo = nvme_getgeo,
+ .revalidate_disk= nvme_revalidate_disk,
++#ifdef HAVE_PR_H
+ .pr_ops = &nvme_pr_ops,
++#endif
+ };
+
+ #ifdef CONFIG_NVME_MULTIPATH
+@@ -1789,7 +2037,12 @@ static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
+ if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
+ is_power_of_2(ctrl->max_hw_sectors))
+ blk_queue_chunk_sectors(q, ctrl->max_hw_sectors);
++#ifdef HAVE_BLK_QUEUE_VIRT_BOUNDARY
+ blk_queue_virt_boundary(q, ctrl->page_size - 1);
++#else
++ if (!ctrl->sg_gaps_support)
++ queue_flag_set_unlocked(QUEUE_FLAG_SG_GAPS, q);
++#endif
+ if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
+ vwc = true;
+ blk_queue_write_cache(q, vwc, vwc);
+@@ -1812,6 +2065,7 @@ static int nvme_configure_timestamp(struct nvme_ctrl *ctrl)
+ return ret;
+ }
+
++#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
+ static int nvme_configure_apst(struct nvme_ctrl *ctrl)
+ {
+ /*
+@@ -1955,6 +2209,7 @@ static void nvme_set_latency_tolerance(struct device *dev, s32 val)
+ nvme_configure_apst(ctrl);
+ }
+ }
++#endif
+
+ struct nvme_core_quirk_entry {
+ /*
+@@ -2287,7 +2542,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
+ u64 cap;
+ int ret, page_shift;
+ u32 max_hw_sectors;
++#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
+ bool prev_apst_enabled;
++#endif
+
+ ret = ctrl->ops->reg_read32(ctrl, NVME_REG_VS, &ctrl->vs);
+ if (ret) {
+@@ -2373,6 +2630,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
+ } else
+ ctrl->shutdown_timeout = shutdown_timeout;
+
++#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
+ ctrl->npss = id->npss;
+ ctrl->apsta = id->apsta;
+ prev_apst_enabled = ctrl->apst_enabled;
+@@ -2387,6 +2645,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
+ ctrl->apst_enabled = id->apsta;
+ }
+ memcpy(ctrl->psd, id->psd, sizeof(ctrl->psd));
++#endif
+
+ if (ctrl->ops->flags & NVME_F_FABRICS) {
+ ctrl->icdoff = le16_to_cpu(id->icdoff);
+@@ -2419,6 +2678,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
+
+ kfree(id);
+
++#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
+ if (ctrl->apst_enabled && !prev_apst_enabled)
+ dev_pm_qos_expose_latency_tolerance(ctrl->device);
+ else if (!ctrl->apst_enabled && prev_apst_enabled)
+@@ -2427,14 +2687,17 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
+ ret = nvme_configure_apst(ctrl);
+ if (ret < 0)
+ return ret;
++#endif
+
+ ret = nvme_configure_timestamp(ctrl);
+ if (ret < 0)
+ return ret;
+
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ ret = nvme_configure_directives(ctrl);
+ if (ret < 0)
+ return ret;
++#endif
+
+ ctrl->identified = true;
+
+@@ -2571,8 +2834,10 @@ static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
+ int serial_len = sizeof(subsys->serial);
+ int model_len = sizeof(subsys->model);
+
++#ifdef HAVE_UUID_IS_NULL
+ if (!uuid_is_null(&ids->uuid))
+ return sprintf(buf, "uuid.%pU\n", &ids->uuid);
++#endif
+
+ if (memchr_inv(ids->nguid, 0, sizeof(ids->nguid)))
+ return sprintf(buf, "eui.%16phN\n", ids->nguid);
+@@ -2593,12 +2858,14 @@ static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
+ }
+ static DEVICE_ATTR_RO(wwid);
+
++#ifdef HAVE_UUID_IS_NULL
+ static ssize_t nguid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+ {
+ return sprintf(buf, "%pU\n", dev_to_ns_head(dev)->ids.nguid);
+ }
+ static DEVICE_ATTR_RO(nguid);
++#endif
+
+ static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+@@ -2608,11 +2875,13 @@ static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
+ /* For backward compatibility expose the NGUID to userspace if
+ * we have no UUID set
+ */
++#ifdef HAVE_UUID_IS_NULL
+ if (uuid_is_null(&ids->uuid)) {
+ printk_ratelimited(KERN_WARNING
+ "No UUID available providing old NGUID\n");
+ return sprintf(buf, "%pU\n", ids->nguid);
+ }
++#endif
+ return sprintf(buf, "%pU\n", &ids->uuid);
+ }
+ static DEVICE_ATTR_RO(uuid);
+@@ -2634,7 +2903,9 @@ static DEVICE_ATTR_RO(nsid);
+ static struct attribute *nvme_ns_id_attrs[] = {
+ &dev_attr_wwid.attr,
+ &dev_attr_uuid.attr,
++#ifdef HAVE_UUID_IS_NULL
+ &dev_attr_nguid.attr,
++#endif
+ &dev_attr_eui.attr,
+ &dev_attr_nsid.attr,
+ NULL,
+@@ -2647,11 +2918,13 @@ static umode_t nvme_ns_id_attrs_are_visible(struct kobject *kobj,
+ struct nvme_ns_ids *ids = &dev_to_ns_head(dev)->ids;
+
+ if (a == &dev_attr_uuid.attr) {
++#ifdef HAVE_UUID_IS_NULL
+ if (uuid_is_null(&ids->uuid) &&
+ !memchr_inv(ids->nguid, 0, sizeof(ids->nguid)))
+ return 0;
+ }
+ if (a == &dev_attr_nguid.attr) {
++#endif
+ if (!memchr_inv(ids->nguid, 0, sizeof(ids->nguid)))
+ return 0;
+ }
+@@ -2692,6 +2965,7 @@ static DEVICE_ATTR(field, S_IRUGO, field##_show, NULL);
+
+ nvme_show_int_function(cntlid);
+
++#ifdef HAVE_DEVICE_REMOVE_FILE_SELF
+ static ssize_t nvme_sysfs_delete(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+@@ -2702,6 +2976,33 @@ static ssize_t nvme_sysfs_delete(struct device *dev,
+ nvme_delete_ctrl_sync(ctrl);
+ return count;
+ }
++#else
++static void nvme_delete_callback(struct device *dev)
++{
++ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
++
++ nvme_delete_ctrl_sync(ctrl);
++}
++
++static ssize_t nvme_sysfs_delete(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t count)
++{
++ int ret;
++
++ /* An attribute cannot be unregistered by one of its own methods,
++ * so we have to use this roundabout approach.
++ */
++ ret = device_schedule_callback(dev, nvme_delete_callback);
++ if (ret)
++ count = ret;
++ else
++ /* Wait for nvme_delete_callback() to finish */
++ msleep(500);
++
++ return count;
++}
++#endif
+ static DEVICE_ATTR(delete_controller, S_IWUSR, NULL, nvme_sysfs_delete);
+
+ static ssize_t nvme_sysfs_show_transport(struct device *dev,
+@@ -2843,6 +3144,9 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
+ goto out_free_head;
+ head->instance = ret;
+ INIT_LIST_HEAD(&head->list);
++#ifndef HAVE_CLEANUP_SRCU_STRUCT_QUIESCED
++ INIT_WORK(&head->free_work, nvme_free_ns_head_work);
++#endif
+ ret = init_srcu_struct(&head->srcu);
+ if (ret)
+ goto out_ida_remove;
+@@ -2943,6 +3247,7 @@ static struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+ return ret;
+ }
+
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
+ {
+ struct streams_directive_params s;
+@@ -2968,6 +3273,7 @@ static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
+
+ return 0;
+ }
++#endif
+
+ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+ {
+@@ -3003,7 +3309,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+
+ if (nvme_init_ns_head(ns, nsid, id))
+ goto out_free_id;
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ nvme_setup_streams_ns(ctrl, ns);
++#endif
+ nvme_set_disk_name(disk_name, ns, ctrl, &flags);
+
+ if ((ctrl->quirks & NVME_QUIRK_LIGHTNVM) && id->vs[0] == 0x1) {
+@@ -3020,6 +3328,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+ disk->fops = &nvme_fops;
+ disk->private_data = ns;
+ disk->queue = ns->queue;
++#ifndef HAVE_DEVICE_ADD_DISK
++ disk->driverfs_dev = ctrl->device;
++#endif
+ disk->flags = flags;
+ memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
+ ns->disk = disk;
+@@ -3034,7 +3345,11 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+
+ kfree(id);
+
++#ifdef HAVE_DEVICE_ADD_DISK
+ device_add_disk(ctrl->device, ns->disk);
++#else
++ add_disk(ns->disk);
++#endif
+ if (sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
+ &nvme_ns_id_attr_group))
+ pr_warn("%s: failed to create sysfs group for identification\n",
+@@ -3457,9 +3772,11 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
+ * Initialize latency tolerance controls. The sysfs files won't
+ * be visible to userspace unless the device actually supports APST.
+ */
++#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
+ ctrl->device->power.set_latency_tolerance = nvme_set_latency_tolerance;
+ dev_pm_qos_update_user_latency_tolerance(ctrl->device,
+ min(default_ps_max_latency_us, (unsigned long)S32_MAX));
++#endif
+
+ return 0;
+ out_free_name:
+@@ -3486,7 +3803,11 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
+
+ /* Forcibly unquiesce queues to avoid blocking dispatch */
+ if (ctrl->admin_q)
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ctrl->admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(ctrl->admin_q, true);
++#endif
+
+ list_for_each_entry(ns, &ctrl->namespaces, list) {
+ /*
+@@ -3499,7 +3820,11 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
+ blk_set_queue_dying(ns->queue);
+
+ /* Forcibly unquiesce queues to avoid blocking dispatch */
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ns->queue);
++#else
++ blk_mq_start_stopped_hw_queues(ns->queue, true);
++#endif
+ }
+ up_read(&ctrl->namespaces_rwsem);
+ }
+@@ -3547,7 +3872,11 @@ void nvme_start_freeze(struct nvme_ctrl *ctrl)
+
+ down_read(&ctrl->namespaces_rwsem);
+ list_for_each_entry(ns, &ctrl->namespaces, list)
++#ifdef HAVE_BLK_FREEZE_QUEUE_START
+ blk_freeze_queue_start(ns->queue);
++#else
++ blk_mq_freeze_queue_start(ns->queue);
++#endif
+ up_read(&ctrl->namespaces_rwsem);
+ }
+ EXPORT_SYMBOL_GPL(nvme_start_freeze);
+@@ -3557,8 +3886,15 @@ void nvme_stop_queues(struct nvme_ctrl *ctrl)
+ struct nvme_ns *ns;
+
+ down_read(&ctrl->namespaces_rwsem);
++#ifdef HAVE_BLK_MQ_QUIESCE_QUEUE
+ list_for_each_entry(ns, &ctrl->namespaces, list)
+ blk_mq_quiesce_queue(ns->queue);
++#else
++ list_for_each_entry(ns, &ctrl->namespaces, list) {
++ blk_mq_cancel_requeue_work(ns->queue);
++ blk_mq_stop_hw_queues(ns->queue);
++ }
++#endif
+ up_read(&ctrl->namespaces_rwsem);
+ }
+ EXPORT_SYMBOL_GPL(nvme_stop_queues);
+@@ -3569,20 +3905,30 @@ void nvme_start_queues(struct nvme_ctrl *ctrl)
+
+ down_read(&ctrl->namespaces_rwsem);
+ list_for_each_entry(ns, &ctrl->namespaces, list)
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ns->queue);
++#else
++ blk_mq_start_stopped_hw_queues(ns->queue, true);
++#endif
+ up_read(&ctrl->namespaces_rwsem);
+ }
+ EXPORT_SYMBOL_GPL(nvme_start_queues);
+
++#if defined(HAVE_BLK_MQ_TAGSET_ITER) || defined(HAVE_BLK_MQ_REINIT_TAGSET_2_PARAM)
+ int nvme_reinit_tagset(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set)
+ {
+ if (!ctrl->ops->reinit_request)
+ return 0;
+
++#ifdef HAVE_BLK_MQ_TAGSET_ITER
+ return blk_mq_tagset_iter(set, set->driver_data,
+ ctrl->ops->reinit_request);
++#else
++ return blk_mq_reinit_tagset(set, ctrl->ops->reinit_request);
++#endif
+ }
+ EXPORT_SYMBOL_GPL(nvme_reinit_tagset);
++#endif
+
+ int __init nvme_core_init(void)
+ {
+diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/nvme/host/fabrics.c
++++ b/drivers/nvme/host/fabrics.c
+@@ -11,6 +11,9 @@
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/init.h>
+ #include <linux/miscdevice.h>
+@@ -158,8 +161,13 @@ int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val)
+ cmd.prop_get.fctype = nvme_fabrics_type_property_get;
+ cmd.prop_get.offset = cpu_to_le32(off);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res, NULL, 0, 0,
+ NVME_QID_ANY, 0, 0);
++#else
++ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res, NULL, 0, 0,
++ NVME_QID_ANY, 0, GFP_KERNEL, false);
++#endif
+
+ if (ret >= 0)
+ *val = le64_to_cpu(res.u64);
+@@ -205,8 +213,13 @@ int nvmf_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val)
+ cmd.prop_get.attrib = 1;
+ cmd.prop_get.offset = cpu_to_le32(off);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res, NULL, 0, 0,
+ NVME_QID_ANY, 0, 0);
++#else
++ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res, NULL, 0, 0,
++ NVME_QID_ANY, 0, GFP_KERNEL, false);
++#endif
+
+ if (ret >= 0)
+ *val = le64_to_cpu(res.u64);
+@@ -251,8 +264,13 @@ int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val)
+ cmd.prop_set.offset = cpu_to_le32(off);
+ cmd.prop_set.value = cpu_to_le64(val);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, NULL, 0, 0,
+ NVME_QID_ANY, 0, 0);
++#else
++ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, NULL, 0, 0,
++ NVME_QID_ANY, 0, GFP_KERNEL, false);
++#endif
+ if (unlikely(ret))
+ dev_err(ctrl->device,
+ "Property Set error: %d, offset %#x\n",
+@@ -401,9 +419,15 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
+ strncpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE);
+ strncpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res,
+ data, sizeof(*data), 0, NVME_QID_ANY, 1,
+ BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
++#else
++ ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res,
++ data, sizeof(*data), 0, NVME_QID_ANY, 1,
++ GFP_ATOMIC, true);
++#endif
+ if (ret) {
+ nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
+ &cmd, data);
+@@ -460,9 +484,15 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid)
+ strncpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE);
+ strncpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ ret = __nvme_submit_sync_cmd(ctrl->connect_q, &cmd, &res,
+ data, sizeof(*data), 0, qid, 1,
+ BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
++#else
++ ret = __nvme_submit_sync_cmd(ctrl->connect_q, &cmd, &res,
++ data, sizeof(*data), 0, qid, 1,
++ GFP_ATOMIC, true);
++#endif
+ if (ret) {
+ nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
+ &cmd, data);
+@@ -606,8 +636,13 @@ reject_or_queue_io:
+ * marked for failfast.
+ * Note: nvme cli/ioctl commands are marked for failfast.
+ */
++#ifdef CONFIG_NVME_MULTIPATH
+ if (!blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
+ return BLK_STS_RESOURCE;
++#else
++ if (!blk_noretry_request(rq))
++ return BLK_STS_RESOURCE;
++#endif
+
+ reject_io:
+ nvme_req(rq)->status = NVME_SC_ABORT_REQ;
+@@ -644,7 +679,11 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
+
+ /* Set defaults */
+ opts->queue_size = NVMF_DEF_QUEUE_SIZE;
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HCTX
+ opts->nr_io_queues = num_online_cpus();
++#else
++ opts->nr_io_queues = 1;
++#endif
+ opts->reconnect_delay = NVMF_DEF_RECONNECT_DELAY;
+ opts->kato = NVME_DEFAULT_KATO;
+ opts->duplicate_connect = false;
+diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/nvme/host/fc.c
++++ b/drivers/nvme/host/fc.c
+@@ -14,6 +14,11 @@
+ * can be found in the file COPYING included with this package
+ *
+ */
++#ifdef HAVE_LINUX_NVME_FC_DRIVER_H
++
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/module.h>
+ #include <linux/parser.h>
+@@ -1497,6 +1502,7 @@ __nvme_fc_exit_request(struct nvme_fc_ctrl *ctrl,
+ atomic_set(&op->state, FCPOP_STATE_UNINIT);
+ }
+
++#ifdef HAVE_BLK_MQ_OPS_EXIT_REQUEST_HAS_3_PARAMS
+ static void
+ nvme_fc_exit_request(struct blk_mq_tag_set *set, struct request *rq,
+ unsigned int hctx_idx)
+@@ -1505,6 +1511,16 @@ nvme_fc_exit_request(struct blk_mq_tag_set *set, struct request *rq,
+
+ return __nvme_fc_exit_request(set->driver_data, op);
+ }
++#else
++static void
++nvme_fc_exit_request(void *data, struct request *rq,
++ unsigned int hctx_idx, unsigned int rq_idx)
++{
++ struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
++
++ __nvme_fc_exit_request(data, op);
++}
++#endif
+
+ static int
+ __nvme_fc_abort_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_fcp_op *op)
+@@ -1752,6 +1768,7 @@ out_on_error:
+ return ret;
+ }
+
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ static int
+ nvme_fc_init_request(struct blk_mq_tag_set *set, struct request *rq,
+ unsigned int hctx_idx, unsigned int numa_node)
+@@ -1763,6 +1780,31 @@ nvme_fc_init_request(struct blk_mq_tag_set *set, struct request *rq,
+
+ return __nvme_fc_init_request(ctrl, queue, op, rq, queue->rqcnt++);
+ }
++#else
++static int
++nvme_fc_init_request(void *data, struct request *rq,
++ unsigned int hctx_idx, unsigned int rq_idx,
++ unsigned int numa_node)
++{
++ struct nvme_fc_ctrl *ctrl = data;
++ struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
++ struct nvme_fc_queue *queue = &ctrl->queues[hctx_idx+1];
++
++ return __nvme_fc_init_request(ctrl, queue, op, rq, queue->rqcnt++);
++}
++
++static int
++nvme_fc_init_admin_request(void *data, struct request *rq,
++ unsigned int hctx_idx, unsigned int rq_idx,
++ unsigned int numa_node)
++{
++ struct nvme_fc_ctrl *ctrl = data;
++ struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
++ struct nvme_fc_queue *queue = &ctrl->queues[0];
++
++ return __nvme_fc_init_request(ctrl, queue, op, rq, queue->rqcnt++);
++}
++#endif
+
+ static int
+ nvme_fc_init_aen_ops(struct nvme_fc_ctrl *ctrl)
+@@ -2014,7 +2056,11 @@ nvme_fc_ctrl_free(struct kref *ref)
+ list_del(&ctrl->ctrl_list);
+ spin_unlock_irqrestore(&ctrl->rport->lock, flags);
+
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(ctrl->ctrl.admin_q, true);
++#endif
+ blk_cleanup_queue(ctrl->ctrl.admin_q);
+ blk_mq_free_tag_set(&ctrl->admin_tag_set);
+
+@@ -2104,12 +2150,24 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
+
+ freq->sg_cnt = 0;
+
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ if (!blk_rq_payload_bytes(rq))
+ return 0;
++#else
++ if (!nvme_map_len(rq))
++ return 0;
++#endif
+
+ freq->sg_table.sgl = freq->first_sgl;
++#ifdef HAVE_SG_ALLOC_TABLE_CHAINED_4_PARAMS
++ ret = sg_alloc_table_chained(&freq->sg_table,
++ blk_rq_nr_phys_segments(rq),
++ GFP_ATOMIC,
++ freq->sg_table.sgl);
++#else
+ ret = sg_alloc_table_chained(&freq->sg_table,
+ blk_rq_nr_phys_segments(rq), freq->sg_table.sgl);
++#endif
+ if (ret)
+ return -ENOMEM;
+
+@@ -2302,7 +2360,11 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
+ if (ret)
+ return ret;
+
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ data_len = blk_rq_payload_bytes(rq);
++#else
++ data_len = nvme_map_len(rq);
++#endif
+ if (data_len)
+ io_dir = ((rq_data_dir(rq) == WRITE) ?
+ NVMEFC_FCP_WRITE : NVMEFC_FCP_READ);
+@@ -2312,6 +2374,7 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
+ return nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+ }
+
++#ifdef HAVE_BLK_MQ_POLL
+ static struct blk_mq_tags *
+ nvme_fc_tagset(struct nvme_fc_queue *queue)
+ {
+@@ -2343,6 +2406,7 @@ nvme_fc_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
+
+ return ((atomic_read(&op->state) != FCPOP_STATE_ACTIVE));
+ }
++#endif
+
+ static void
+ nvme_fc_submit_async_event(struct nvme_ctrl *arg)
+@@ -2415,8 +2479,13 @@ static const struct blk_mq_ops nvme_fc_mq_ops = {
+ .complete = nvme_fc_complete_rq,
+ .init_request = nvme_fc_init_request,
+ .exit_request = nvme_fc_exit_request,
++#ifdef HAVE_BLK_MQ_OPS_REINIT_REQUEST
++ .reinit_request = nvme_fc_reinit_request,
++#endif
+ .init_hctx = nvme_fc_init_hctx,
++#ifdef HAVE_BLK_MQ_POLL
+ .poll = nvme_fc_poll,
++#endif
+ .timeout = nvme_fc_timeout,
+ };
+
+@@ -2515,7 +2584,11 @@ nvme_fc_reinit_io_queues(struct nvme_fc_ctrl *ctrl)
+
+ nvme_fc_init_io_queues(ctrl);
+
++#if defined(HAVE_BLK_MQ_TAGSET_ITER) || defined(HAVE_BLK_MQ_REINIT_TAGSET_2_PARAM)
+ ret = nvme_reinit_tagset(&ctrl->ctrl, ctrl->ctrl.tagset);
++#else
++ ret = blk_mq_reinit_tagset(&ctrl->tag_set);
++#endif
+ if (ret)
+ goto out_free_io_queues;
+
+@@ -2629,7 +2702,11 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
+ goto out_delete_hw_queue;
+
+ if (ctrl->ctrl.state != NVME_CTRL_NEW)
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(ctrl->ctrl.admin_q, true);
++#endif
+
+ ret = nvmf_connect_admin_queue(&ctrl->ctrl);
+ if (ret)
+@@ -2790,7 +2867,11 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl)
+ * terminate the exchanges.
+ */
+ if (ctrl->ctrl.state != NVME_CTRL_NEW)
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_stop_hw_queues(ctrl->ctrl.admin_q);
++#endif
+ blk_mq_tagset_busy_iter(&ctrl->admin_tag_set,
+ nvme_fc_terminate_exchange, &ctrl->ctrl);
+
+@@ -2823,7 +2904,11 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl)
+ nvme_fc_free_queue(&ctrl->queues[0]);
+
+ /* re-enable the admin_q so anything new can fast fail */
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(ctrl->ctrl.admin_q, true);
++#endif
+
+ nvme_fc_ctlr_inactive_on_rport(ctrl);
+ }
+@@ -2955,8 +3040,15 @@ nvme_fc_connect_ctrl_work(struct work_struct *work)
+ static const struct blk_mq_ops nvme_fc_admin_mq_ops = {
+ .queue_rq = nvme_fc_queue_rq,
+ .complete = nvme_fc_complete_rq,
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ .init_request = nvme_fc_init_request,
++#else
++ .init_request = nvme_fc_init_admin_request,
++#endif
+ .exit_request = nvme_fc_exit_request,
++#ifdef HAVE_BLK_MQ_OPS_REINIT_REQUEST
++ .reinit_request = nvme_fc_reinit_request,
++#endif
+ .init_hctx = nvme_fc_init_admin_hctx,
+ .timeout = nvme_fc_timeout,
+ };
+@@ -3064,7 +3156,9 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
+ ctrl->admin_tag_set.driver_data = ctrl;
+ ctrl->admin_tag_set.nr_hw_queues = 1;
+ ctrl->admin_tag_set.timeout = ADMIN_TIMEOUT;
++#ifdef HAVE_BLK_MQ_F_NO_SCHED
+ ctrl->admin_tag_set.flags = BLK_MQ_F_NO_SCHED;
++#endif
+
+ ret = blk_mq_alloc_tag_set(&ctrl->admin_tag_set);
+ if (ret)
+@@ -3363,3 +3457,4 @@ module_init(nvme_fc_init_module);
+ module_exit(nvme_fc_exit_module);
+
+ MODULE_LICENSE("GPL v2");
++#endif /* HAVE_LINUX_NVME_FC_DRIVER_H */
+diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/nvme/host/lightnvm.c
++++ b/drivers/nvme/host/lightnvm.c
+@@ -20,14 +20,18 @@
+ *
+ */
+
++#ifdef HAVE_LIGHTNVM_NVM_DEV
++
+ #include "nvme.h"
+
+ #include <linux/nvme.h>
+ #include <linux/bitops.h>
+ #include <linux/lightnvm.h>
+ #include <linux/vmalloc.h>
++#ifdef HAVE_NVM_USER_VIO
+ #include <linux/sched/sysctl.h>
+ #include <uapi/linux/lightnvm.h>
++#endif
+
+ enum nvme_nvm_admin_opcode {
+ nvme_nvm_admin_identity = 0xe2,
+@@ -1307,3 +1311,5 @@ void nvme_nvm_unregister_sysfs(struct nvme_ns *ns)
+ break;
+ }
+ }
++
++#endif /* HAVE_LIGHTNVM_NVM_DEV */
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -19,8 +19,12 @@
+ #include <linux/pci.h>
+ #include <linux/kref.h>
+ #include <linux/blk-mq.h>
++#ifdef HAVE_LIGHTNVM_H
+ #include <linux/lightnvm.h>
++#endif
++#ifdef HAVE_LINUX_SED_OPAL_H
+ #include <linux/sed-opal.h>
++#endif
+ #include <linux/fault-inject.h>
+
+ extern unsigned int nvme_io_timeout;
+@@ -58,11 +62,19 @@ enum nvme_quirks {
+ */
+ NVME_QUIRK_IDENTIFY_CNS = (1 << 1),
+
++#ifdef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
+ /*
+ * The controller deterministically returns O's on reads to
+ * logical blocks that deallocate was called on.
+ */
+ NVME_QUIRK_DEALLOCATE_ZEROES = (1 << 2),
++#else
++ /*
++ * The controller deterministically returns O's on reads to discarded
++ * logical blocks.
++ */
++ NVME_QUIRK_DISCARD_ZEROES = (1 << 2),
++#endif
+
+ /*
+ * The controller needs a delay before starts checking the device
+@@ -157,7 +169,9 @@ struct nvme_ctrl {
+ struct nvme_subsystem *subsys;
+ struct list_head subsys_entry;
+
++#ifdef HAVE_LINUX_SED_OPAL_H
+ struct opal_dev *opal_dev;
++#endif
+
+ char name[12];
+ u16 cntlid;
+@@ -171,8 +185,10 @@ struct nvme_ctrl {
+ u32 max_hw_sectors;
+ u16 oncs;
+ u16 oacs;
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ u16 nssa;
+ u16 nr_streams;
++#endif
+ atomic_t abort_limit;
+ u8 vwc;
+ u32 vs;
+@@ -266,6 +282,9 @@ struct nvme_ns_head {
+ struct list_head entry;
+ struct kref ref;
+ int instance;
++#ifndef HAVE_CLEANUP_SRCU_STRUCT_QUIESCED
++ struct work_struct free_work;
++#endif
+ };
+
+ #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+@@ -290,8 +309,10 @@ struct nvme_ns {
+
+ int lba_shift;
+ u16 ms;
++#ifdef HAVE_BLK_MAX_WRITE_HINTS
+ u16 sgs;
+ u32 sws;
++#endif
+ bool ext;
+ u8 pi_type;
+ unsigned long flags;
+@@ -353,12 +374,35 @@ static inline u64 nvme_block_nr(struct nvme_ns *ns, sector_t sector)
+ return (sector >> (ns->lba_shift - 9));
+ }
+
++#ifndef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
++static inline unsigned nvme_map_len(struct request *rq)
++{
++#ifdef HAVE_BLK_TYPES_REQ_OP_DISCARD
++ if (req_op(rq) == REQ_OP_DISCARD)
++#else
++ if (rq->cmd_flags & REQ_DISCARD)
++#endif
++ return sizeof(struct nvme_dsm_range);
++ else
++ return blk_rq_bytes(rq);
++}
++#endif
++
+ static inline void nvme_cleanup_cmd(struct request *req)
+ {
++#ifdef HAVE_REQUEST_RQ_FLAGS
+ if (req->rq_flags & RQF_SPECIAL_PAYLOAD) {
+ kfree(page_address(req->special_vec.bv_page) +
+ req->special_vec.bv_offset);
+ }
++#else
++#ifdef HAVE_BLK_TYPES_REQ_OP_DISCARD
++ if (req_op(req) == REQ_OP_DISCARD)
++#else
++ if (req->cmd_flags & REQ_DISCARD)
++#endif
++ kfree(req->completion_data);
++#endif
+ }
+
+ static inline void nvme_end_request(struct request *req, __le16 status,
+@@ -370,7 +414,11 @@ static inline void nvme_end_request(struct request *req, __le16 status,
+ rq->result = result;
+ /* inject error when permitted by fault injection framework */
+ nvme_should_fail(req);
++#ifdef HAVE_BLK_MQ_COMPLETE_REQUEST_HAS_2_PARAMS
++ blk_mq_complete_request(req, 0);
++#else
+ blk_mq_complete_request(req);
++#endif
+ }
+
+ static inline void nvme_get_ctrl(struct nvme_ctrl *ctrl)
+@@ -401,8 +449,10 @@ int nvme_init_identify(struct nvme_ctrl *ctrl);
+ void nvme_queue_scan(struct nvme_ctrl *ctrl);
+ void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
+
++#ifdef HAVE_LINUX_SED_OPAL_H
+ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
+ bool send);
++#endif
+
+ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
+ union nvme_result *res);
+@@ -417,16 +467,27 @@ void nvme_start_freeze(struct nvme_ctrl *ctrl);
+ int nvme_reinit_tagset(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set);
+
+ #define NVME_QID_ANY -1
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ struct request *nvme_alloc_request(struct request_queue *q,
+ struct nvme_command *cmd, blk_mq_req_flags_t flags, int qid);
++#else
++struct request *nvme_alloc_request(struct request_queue *q,
++ struct nvme_command *cmd, gfp_t gfp, bool reserved, int qid);
++#endif
+ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
+ struct nvme_command *cmd);
+ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+ void *buf, unsigned bufflen);
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+ union nvme_result *result, void *buffer, unsigned bufflen,
+ unsigned timeout, int qid, int at_head,
+ blk_mq_req_flags_t flags);
++#else
++int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
++ union nvme_result *result, void *buffer, unsigned bufflen,
++ unsigned timeout, int qid, int at_head, gfp_t gfp, bool reserved);
++#endif
+ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count);
+ void nvme_stop_keep_alive(struct nvme_ctrl *ctrl);
+ int nvme_reset_ctrl(struct nvme_ctrl *ctrl);
+@@ -508,13 +569,15 @@ static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
+ }
+ #endif /* CONFIG_NVME_MULTIPATH */
+
+-#ifdef CONFIG_NVM
++#if defined(CONFIG_NVM) && defined(HAVE_LIGHTNVM_NVM_DEV)
+ void nvme_nvm_update_nvm_info(struct nvme_ns *ns);
+ int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node);
+ void nvme_nvm_unregister(struct nvme_ns *ns);
+ int nvme_nvm_register_sysfs(struct nvme_ns *ns);
+ void nvme_nvm_unregister_sysfs(struct nvme_ns *ns);
++#ifdef HAVE_NVM_USER_VIO
+ int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg);
++#endif
+ #else
+ static inline void nvme_nvm_update_nvm_info(struct nvme_ns *ns) {};
+ static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name,
+@@ -529,11 +592,13 @@ static inline int nvme_nvm_register_sysfs(struct nvme_ns *ns)
+ return 0;
+ }
+ static inline void nvme_nvm_unregister_sysfs(struct nvme_ns *ns) {};
++#ifdef HAVE_NVM_USER_VIO
+ static inline int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd,
+ unsigned long arg)
+ {
+ return -ENOTTY;
+ }
++#endif
+ #endif /* CONFIG_NVM */
+
+ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
+@@ -544,4 +609,15 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
+ int __init nvme_core_init(void);
+ void nvme_core_exit(void);
+
++#ifndef HAVE_BLK_RQ_NR_PHYS_SEGMENTS
++static inline unsigned short blk_rq_nr_phys_segments(struct request *rq)
++{
++#ifdef HAVE_REQUEST_RQ_FLAGS
++ if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
++ return 1;
++#endif
++ return rq->nr_phys_segments;
++}
++#endif
++
+ #endif /* _NVME_H */
+diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/nvme/host/pci.c
++++ b/drivers/nvme/host/pci.c
+@@ -23,12 +23,21 @@
+ #include <linux/mm.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
++#ifdef HAVE_ONCE_H
+ #include <linux/once.h>
++#endif
+ #include <linux/pci.h>
+ #include <linux/t10-pi.h>
+ #include <linux/types.h>
++#ifdef HAVE_IO_64_NONATOMIC_LO_HI_H
+ #include <linux/io-64-nonatomic-lo-hi.h>
++#else
++#include <asm-generic/io-64-nonatomic-lo-hi.h>
++#endif
++#ifdef HAVE_LINUX_SED_OPAL_H
+ #include <linux/sed-opal.h>
++#endif
++#include <linux/sizes.h>
+
+ #include "nvme.h"
+
+@@ -84,16 +93,25 @@ struct nvme_dev {
+ struct dma_pool *prp_small_pool;
+ unsigned online_queues;
+ unsigned max_qid;
++#if defined(HAVE_PCI_IRQ_API) && defined(HAVE_IRQ_CALC_AFFINITY_VECTORS_3_ARGS)
+ unsigned int num_vecs;
++#endif
+ int q_depth;
+ u32 db_stride;
++#ifndef HAVE_PCI_IRQ_API
++ struct msix_entry *entry;
++#endif
+ void __iomem *bar;
+ unsigned long bar_mapped_size;
+ struct work_struct remove_work;
+ struct mutex shutdown_lock;
+ bool subsystem;
+ void __iomem *cmb;
++#ifdef HAVE_PCI_BUS_ADDR_T
+ pci_bus_addr_t cmb_bus_addr;
++#else
++ dma_addr_t cmb_dma_addr;
++#endif
+ u64 cmb_size;
+ u32 cmbsz;
+ u32 cmbloc;
+@@ -147,6 +165,9 @@ static inline struct nvme_dev *to_nvme_dev(struct nvme_ctrl *ctrl)
+ struct nvme_queue {
+ struct device *q_dmadev;
+ struct nvme_dev *dev;
++#ifndef HAVE_PCI_FREE_IRQ
++ char irqname[24]; /* nvme4294967295-65535\0 */
++#endif
+ spinlock_t q_lock;
+ struct nvme_command *sq_cmds;
+ struct nvme_command __iomem *sq_cmds_io;
+@@ -362,6 +383,17 @@ static unsigned int nvme_pci_cmd_size(struct nvme_dev *dev, bool use_sgl)
+ return sizeof(struct nvme_iod) + alloc_size;
+ }
+
++#ifndef HAVE_PCI_FREE_IRQ
++static int nvmeq_irq(struct nvme_queue *nvmeq)
++{
++#ifdef HAVE_PCI_IRQ_API
++ return pci_irq_vector(to_pci_dev(nvmeq->dev->dev), nvmeq->cq_vector);
++#else
++ return nvmeq->dev->entry[nvmeq->cq_vector].vector;
++#endif
++}
++#endif
++
+ static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
+ unsigned int hctx_idx)
+ {
+@@ -398,6 +430,7 @@ static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
+ return 0;
+ }
+
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ static int nvme_init_request(struct blk_mq_tag_set *set, struct request *req,
+ unsigned int hctx_idx, unsigned int numa_node)
+ {
+@@ -410,14 +443,56 @@ static int nvme_init_request(struct blk_mq_tag_set *set, struct request *req,
+ iod->nvmeq = nvmeq;
+ return 0;
+ }
++#else
++static int nvme_init_request(void *data, struct request *req,
++ unsigned int hctx_idx, unsigned int rq_idx,
++ unsigned int numa_node)
++{
++ struct nvme_dev *dev = data;
++ struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
++ struct nvme_queue *nvmeq = &dev->queues[hctx_idx + 1];
++
++ BUG_ON(!nvmeq);
++ iod->nvmeq = nvmeq;
++ return 0;
++}
++
++static int nvme_admin_init_request(void *data, struct request *req,
++ unsigned int hctx_idx, unsigned int rq_idx,
++ unsigned int numa_node)
++{
++ struct nvme_dev *dev = data;
++ struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
++ struct nvme_queue *nvmeq = &dev->queues[0];
++
++ BUG_ON(!nvmeq);
++ iod->nvmeq = nvmeq;
++ return 0;
++}
++#endif
+
++#ifdef HAVE_BLK_MQ_OPS_MAP_QUEUES
+ static int nvme_pci_map_queues(struct blk_mq_tag_set *set)
+ {
+ struct nvme_dev *dev = set->driver_data;
+
++#if defined(HAVE_PCI_IRQ_API) && defined(HAVE_IRQ_CALC_AFFINITY_VECTORS_3_ARGS)
++#ifdef HAVE_BLK_MQ_PCI_MAP_QUEUES_3_ARGS
+ return blk_mq_pci_map_queues(set, to_pci_dev(dev->dev),
+ dev->num_vecs > 1 ? 1 /* admin queue */ : 0);
++#else
++ return __blk_mq_pci_map_queues(set, to_pci_dev(dev->dev),
++ dev->num_vecs > 1 ? 1 /* admin queue */ : 0);
++#endif
++#else
++#ifdef HAVE_BLK_MQ_PCI_MAP_QUEUES_3_ARGS
++ return blk_mq_pci_map_queues(set, to_pci_dev(dev->dev), 0);
++#else
++ return __blk_mq_pci_map_queues(set, to_pci_dev(dev->dev), 0);
++#endif
++#endif
+ }
++#endif
+
+ /**
+ * __nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
+@@ -459,7 +534,11 @@ static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req)
+ if (nseg == 0)
+ return false;
+
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ avg_seg_size = DIV_ROUND_UP(blk_rq_payload_bytes(req), nseg);
++#else
++ avg_seg_size = DIV_ROUND_UP(nvme_map_len(req), nseg);
++#endif
+
+ if (!(dev->ctrl.sgls & ((1 << 0) | (1 << 1))))
+ return false;
+@@ -474,7 +553,11 @@ static blk_status_t nvme_init_iod(struct request *rq, struct nvme_dev *dev)
+ {
+ struct nvme_iod *iod = blk_mq_rq_to_pdu(rq);
+ int nseg = blk_rq_nr_phys_segments(rq);
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ unsigned int size = blk_rq_payload_bytes(rq);
++#else
++ unsigned int size = nvme_map_len(rq);
++#endif
+
+ iod->use_sgl = nvme_pci_use_sgls(dev, rq);
+
+@@ -531,7 +614,7 @@ static void nvme_free_iod(struct nvme_dev *dev, struct request *req)
+ kfree(iod->sg);
+ }
+
+-#ifdef CONFIG_BLK_DEV_INTEGRITY
++#if defined(CONFIG_BLK_DEV_INTEGRITY) && defined(HAVE_BLK_TYPES_REQ_INTEGRITY)
+ static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
+ {
+ if (be32_to_cpu(pi->ref_tag) == v)
+@@ -598,6 +681,7 @@ static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
+ }
+ #endif
+
++#ifdef HAVE_ONCE_H
+ static void nvme_print_sgl(struct scatterlist *sgl, int nents)
+ {
+ int i;
+@@ -611,13 +695,18 @@ static void nvme_print_sgl(struct scatterlist *sgl, int nents)
+ sg_dma_len(sg));
+ }
+ }
++#endif
+
+ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
+ struct request *req, struct nvme_rw_command *cmnd)
+ {
+ struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+ struct dma_pool *pool;
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ int length = blk_rq_payload_bytes(req);
++#else
++ int length = nvme_map_len(req);
++#endif
+ struct scatterlist *sg = iod->sg;
+ int dma_len = sg_dma_len(sg);
+ u64 dma_addr = sg_dma_address(sg);
+@@ -699,9 +788,31 @@ done:
+ return BLK_STS_OK;
+
+ bad_sgl:
++#ifdef HAVE_ONCE_H
+ WARN(DO_ONCE(nvme_print_sgl, iod->sg, iod->nents),
+ "Invalid SGL for payload:%d nents:%d\n",
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ blk_rq_payload_bytes(req), iod->nents);
++#else
++ nvme_map_len(req), iod->nents);
++#endif
++#else
++ if (WARN_ONCE(1, "Invalid SGL for payload:%d nents:%d\n",
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
++ blk_rq_payload_bytes(req), iod->nents)) {
++#else
++ nvme_map_len(req), iod->nents)) {
++#endif
++ for_each_sg(iod->sg, sg, iod->nents, i) {
++ dma_addr_t phys = sg_phys(sg);
++ pr_warn("sg[%d] phys_addr:%pad offset:%d length:%d "
++ "dma_address:%pad dma_length:%d\n", i, &phys,
++ sg->offset, sg->length,
++ &sg_dma_address(sg),
++ sg_dma_len(sg));
++ }
++ }
++#endif
+ return BLK_STS_IOERR;
+ }
+
+@@ -801,8 +912,12 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
+ goto out;
+
+ ret = BLK_STS_RESOURCE;
++#ifdef HAVE_DMA_ATTR_NO_WARN
+ nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents, dma_dir,
+ DMA_ATTR_NO_WARN);
++#else
++ nr_mapped = dma_map_sg(dev->dev, iod->sg, iod->nents, dma_dir);
++#endif
+ if (!nr_mapped)
+ goto out;
+
+@@ -823,7 +938,11 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
+ if (blk_rq_map_integrity_sg(q, req->bio, &iod->meta_sg) != 1)
+ goto out_unmap;
+
++#ifdef HAVE_REQ_OP
+ if (req_op(req) == REQ_OP_WRITE)
++#else
++ if (rq_data_dir(req))
++#endif
+ nvme_dif_remap(req, nvme_dif_prep);
+
+ if (!dma_map_sg(dev->dev, &iod->meta_sg, 1, dma_dir))
+@@ -849,7 +968,11 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
+ if (iod->nents) {
+ dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir);
+ if (blk_integrity_rq(req)) {
++#ifdef HAVE_REQ_OP
+ if (req_op(req) == REQ_OP_READ)
++#else
++ if (!rq_data_dir(req))
++#endif
+ nvme_dif_remap(req, nvme_dif_complete);
+ dma_unmap_sg(dev->dev, &iod->meta_sg, 1, dma_dir);
+ }
+@@ -1036,12 +1159,14 @@ static int __nvme_poll(struct nvme_queue *nvmeq, unsigned int tag)
+ return found;
+ }
+
++#ifdef HAVE_BLK_MQ_POLL
+ static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
+ {
+ struct nvme_queue *nvmeq = hctx->driver_data;
+
+ return __nvme_poll(nvmeq, tag);
+ }
++#endif
+
+ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl)
+ {
+@@ -1275,8 +1400,13 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
+ "I/O %d QID %d timeout, aborting\n",
+ req->tag, nvmeq->qid);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ abort_req = nvme_alloc_request(dev->ctrl.admin_q, &cmd,
+ BLK_MQ_REQ_NOWAIT, NVME_QID_ANY);
++#else
++ abort_req = nvme_alloc_request(dev->ctrl.admin_q, &cmd,
++ GFP_KERNEL, reserved, NVME_QID_ANY);
++#endif
+ if (IS_ERR(abort_req)) {
+ atomic_inc(&dev->ctrl.abort_limit);
+ return BLK_EH_RESET_TIMER;
+@@ -1334,7 +1464,11 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq)
+ if (!nvmeq->qid && nvmeq->dev->ctrl.admin_q)
+ blk_mq_quiesce_queue(nvmeq->dev->ctrl.admin_q);
+
++#ifdef HAVE_PCI_FREE_IRQ
+ pci_free_irq(to_pci_dev(nvmeq->dev->dev), vector, nvmeq);
++#else
++ free_irq(vector, nvmeq);
++#endif
+
+ return 0;
+ }
+@@ -1428,6 +1562,7 @@ static int nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth)
+
+ static int queue_request_irq(struct nvme_queue *nvmeq)
+ {
++#ifdef HAVE_PCI_FREE_IRQ
+ struct pci_dev *pdev = to_pci_dev(nvmeq->dev->dev);
+ int nr = nvmeq->dev->ctrl.instance;
+
+@@ -1438,6 +1573,14 @@ static int queue_request_irq(struct nvme_queue *nvmeq)
+ return pci_request_irq(pdev, nvmeq->cq_vector, nvme_irq,
+ NULL, nvmeq, "nvme%dq%d", nr, nvmeq->qid);
+ }
++#else
++ if (use_threaded_interrupts)
++ return request_threaded_irq(nvmeq_irq(nvmeq), nvme_irq_check,
++ nvme_irq, IRQF_SHARED, nvmeq->irqname, nvmeq);
++ else
++ return request_irq(nvmeq_irq(nvmeq), nvme_irq, IRQF_SHARED,
++ nvmeq->irqname, nvmeq);
++#endif
+ }
+
+ static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid)
+@@ -1463,7 +1606,11 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
+ if (dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
+ unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth),
+ dev->ctrl.page_size);
++#ifdef HAVE_PCI_BUS_ADDR_T
+ nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
++#else
++ nvmeq->sq_dma_addr = dev->cmb_dma_addr + offset;
++#endif
+ nvmeq->sq_cmds_io = dev->cmb + offset;
+ }
+
+@@ -1471,7 +1618,11 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
+ * A queue's vector matches the queue identifier unless the controller
+ * has only one vector available.
+ */
++#if defined(HAVE_PCI_IRQ_API) && defined(HAVE_IRQ_CALC_AFFINITY_VECTORS_3_ARGS)
+ nvmeq->cq_vector = dev->num_vecs == 1 ? 0 : qid;
++#else
++ nvmeq->cq_vector = qid - 1;
++#endif
+ result = adapter_alloc_cq(dev, qid, nvmeq);
+ if (result < 0)
+ goto release_vector;
+@@ -1497,23 +1648,39 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
+ return result;
+ }
+
++#ifdef HAVE_BLK_MQ_TAG_SET_HAS_CONST_POS
+ static const struct blk_mq_ops nvme_mq_admin_ops = {
++#else
++static struct blk_mq_ops nvme_mq_admin_ops = {
++#endif
+ .queue_rq = nvme_queue_rq,
+ .complete = nvme_pci_complete_rq,
+ .init_hctx = nvme_admin_init_hctx,
+ .exit_hctx = nvme_admin_exit_hctx,
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ .init_request = nvme_init_request,
++#else
++ .init_request = nvme_admin_init_request,
++#endif
+ .timeout = nvme_timeout,
+ };
+
++#ifdef HAVE_BLK_MQ_TAG_SET_HAS_CONST_POS
+ static const struct blk_mq_ops nvme_mq_ops = {
++#else
++static struct blk_mq_ops nvme_mq_ops = {
++#endif
+ .queue_rq = nvme_queue_rq,
+ .complete = nvme_pci_complete_rq,
+ .init_hctx = nvme_init_hctx,
+ .init_request = nvme_init_request,
++#ifdef HAVE_BLK_MQ_OPS_MAP_QUEUES
+ .map_queues = nvme_pci_map_queues,
++#endif
+ .timeout = nvme_timeout,
++#ifdef HAVE_BLK_MQ_POLL
+ .poll = nvme_poll,
++#endif
+ };
+
+ static void nvme_dev_remove_admin(struct nvme_dev *dev)
+@@ -1524,7 +1691,11 @@ static void nvme_dev_remove_admin(struct nvme_dev *dev)
+ * user requests may be waiting on a stopped queue. Start the
+ * queue to flush these to completion.
+ */
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(dev->ctrl.admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(dev->ctrl.admin_q, true);
++#endif
+ blk_cleanup_queue(dev->ctrl.admin_q);
+ blk_mq_free_tag_set(&dev->admin_tagset);
+ }
+@@ -1540,7 +1711,9 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)
+ dev->admin_tagset.timeout = ADMIN_TIMEOUT;
+ dev->admin_tagset.numa_node = dev_to_node(dev->dev);
+ dev->admin_tagset.cmd_size = nvme_pci_cmd_size(dev, false);
++#ifdef HAVE_BLK_MQ_F_NO_SCHED
+ dev->admin_tagset.flags = BLK_MQ_F_NO_SCHED;
++#endif
+ dev->admin_tagset.driver_data = dev;
+
+ if (blk_mq_alloc_tag_set(&dev->admin_tagset))
+@@ -1558,7 +1731,11 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)
+ return -ENODEV;
+ }
+ } else
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(dev->ctrl.admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(dev->ctrl.admin_q, true);
++#endif
+
+ return 0;
+ }
+@@ -1693,7 +1870,11 @@ static void nvme_map_cmb(struct nvme_dev *dev)
+ u64 size, offset;
+ resource_size_t bar_size;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
++#ifdef HAVE_PCI_BUS_ADDR_T
+ int bar;
++#else
++ dma_addr_t dma_addr;
++#endif
+
+ dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
+ if (!dev->cmbsz)
+@@ -1705,8 +1886,12 @@ static void nvme_map_cmb(struct nvme_dev *dev)
+
+ size = nvme_cmb_size_unit(dev) * nvme_cmb_size(dev);
+ offset = nvme_cmb_size_unit(dev) * NVME_CMB_OFST(dev->cmbloc);
++#ifdef HAVE_PCI_BUS_ADDR_T
+ bar = NVME_CMB_BIR(dev->cmbloc);
+ bar_size = pci_resource_len(pdev, bar);
++#else
++ bar_size = pci_resource_len(pdev, NVME_CMB_BIR(dev->cmbloc));
++#endif
+
+ if (offset > bar_size)
+ return;
+@@ -1719,10 +1904,20 @@ static void nvme_map_cmb(struct nvme_dev *dev)
+ if (size > bar_size - offset)
+ size = bar_size - offset;
+
++#ifdef HAVE_PCI_BUS_ADDR_T
+ dev->cmb = ioremap_wc(pci_resource_start(pdev, bar) + offset, size);
++#else
++ dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(dev->cmbloc)) + offset;
++ dev->cmb = ioremap_wc(dma_addr, size);
++#endif
+ if (!dev->cmb)
+ return;
++
++#ifdef HAVE_PCI_BUS_ADDR_T
+ dev->cmb_bus_addr = pci_bus_address(pdev, bar) + offset;
++#else
++ dev->cmb_dma_addr = dma_addr;
++#endif
+ dev->cmb_size = size;
+
+ if (sysfs_add_file_to_group(&dev->ctrl.device->kobj,
+@@ -1816,10 +2011,26 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
+
+ for (size = 0; size < preferred && i < max_entries; size += len) {
+ dma_addr_t dma_addr;
++#ifndef HAVE_DMA_SET_ATTR_TAKES_UNSIGNED_LONG_ATTRS
++ DEFINE_DMA_ATTRS(attrs);
++#ifdef HAVE_DMA_ATTR_NO_WARN
++ dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_NO_WARN, &attrs);
++#else
++ dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
++#endif
++#endif
+
+ len = min_t(u64, chunk_size, preferred - size);
+ bufs[i] = dma_alloc_attrs(dev->dev, len, &dma_addr, GFP_KERNEL,
++#ifdef HAVE_DMA_SET_ATTR_TAKES_UNSIGNED_LONG_ATTRS
++#ifdef HAVE_DMA_ATTR_NO_WARN
+ DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_NO_WARN);
++#else
++ DMA_ATTR_NO_KERNEL_MAPPING);
++#endif
++#else
++ &attrs);
++#endif
+ if (!bufs[i])
+ break;
+
+@@ -1922,12 +2133,18 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
+ {
+ struct nvme_queue *adminq = &dev->queues[0];
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
++#ifdef HAVE_PCI_IRQ_API
+ int result, nr_io_queues;
++#else
++ int result, i, vecs, nr_io_queues;
++#endif
+ unsigned long size;
+
++#if defined(HAVE_PCI_IRQ_API) && defined(HAVE_IRQ_CALC_AFFINITY_VECTORS_3_ARGS)
+ struct irq_affinity affd = {
+ .pre_vectors = 1
+ };
++#endif
+
+ nr_io_queues = num_possible_cpus();
+ result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues);
+@@ -1957,19 +2174,55 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
+ adminq->q_db = dev->dbs;
+
+ /* Deregister the admin queue's interrupt */
++#ifdef HAVE_PCI_FREE_IRQ
+ pci_free_irq(pdev, 0, adminq);
++#elif defined(HAVE_PCI_IRQ_API)
++ free_irq(pci_irq_vector(pdev, 0), adminq);
++#else
++ free_irq(dev->entry[0].vector, adminq);
++#endif
+
+ /*
+ * If we enable msix early due to not intx, disable it again before
+ * setting up the full range we need.
+ */
++#ifdef HAVE_PCI_IRQ_API
+ pci_free_irq_vectors(pdev);
++#ifdef HAVE_IRQ_CALC_AFFINITY_VECTORS_3_ARGS
+ result = pci_alloc_irq_vectors_affinity(pdev, 1, nr_io_queues + 1,
+ PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd);
+ if (result <= 0)
+ return -EIO;
+ dev->num_vecs = result;
+ dev->max_qid = max(result - 1, 1);
++#else
++ nr_io_queues = pci_alloc_irq_vectors(pdev, 1, nr_io_queues,
++ PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY);
++ if (nr_io_queues <= 0)
++ return -EIO;
++ dev->max_qid = nr_io_queues;
++#endif
++#else
++ if (pdev->msi_enabled)
++ pci_disable_msi(pdev);
++ else if (pdev->msix_enabled)
++ pci_disable_msix(pdev);
++
++ for (i = 0; i < nr_io_queues; i++)
++ dev->entry[i].entry = i;
++ vecs = pci_enable_msix_range(pdev, dev->entry, 1, nr_io_queues);
++ if (vecs < 0) {
++ vecs = pci_enable_msi_range(pdev, 1, min(nr_io_queues, 32u));
++ if (vecs < 0) {
++ vecs = 1;
++ } else {
++ for (i = 0; i < vecs; i++)
++ dev->entry[i].vector = i + pdev->irq;
++ }
++ }
++ nr_io_queues = vecs;
++ dev->max_qid = nr_io_queues;
++#endif
+
+ /*
+ * Should investigate if there's a performance win from allocating
+@@ -2025,7 +2278,11 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
+ cmd.delete_queue.opcode = opcode;
+ cmd.delete_queue.qid = cpu_to_le16(nvmeq->qid);
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+ req = nvme_alloc_request(q, &cmd, BLK_MQ_REQ_NOWAIT, NVME_QID_ANY);
++#else
++ req = nvme_alloc_request(q, &cmd, GFP_KERNEL, false, NVME_QID_ANY);
++#endif
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+@@ -2097,7 +2354,9 @@ static int nvme_dev_add(struct nvme_dev *dev)
+
+ nvme_dbbuf_set(dev);
+ } else {
++#ifdef HAVE_BLK_MQ_UPDATE_NR_HW_QUEUES
+ blk_mq_update_nr_hw_queues(&dev->tagset, dev->online_queues - 1);
++#endif
+
+ /* Free previously allocated queues that are no longer usable */
+ nvme_free_queues(dev, dev->online_queues);
+@@ -2130,9 +2389,21 @@ static int nvme_pci_enable(struct nvme_dev *dev)
+ * interrupts. Pre-enable a single MSIX or MSI vec for setup. We'll
+ * adjust this later.
+ */
++#ifdef HAVE_PCI_IRQ_API
+ result = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (result < 0)
+ return result;
++#else
++ if (pci_enable_msix(pdev, dev->entry, 1)) {
++ pci_enable_msi(pdev);
++ dev->entry[0].vector = pdev->irq;
++ }
++
++ if (!dev->entry[0].vector) {
++ result = -ENODEV;
++ goto disable;
++ }
++#endif
+
+ dev->ctrl.cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
+
+@@ -2181,7 +2452,14 @@ static void nvme_pci_disable(struct nvme_dev *dev)
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ nvme_release_cmb(dev);
++#ifdef HAVE_PCI_IRQ_API
+ pci_free_irq_vectors(pdev);
++#else
++ if (pdev->msi_enabled)
++ pci_disable_msi(pdev);
++ else if (pdev->msix_enabled)
++ pci_disable_msix(pdev);
++#endif
+
+ if (pci_is_enabled(pdev)) {
+ pci_disable_pcie_error_reporting(pdev);
+@@ -2281,7 +2559,12 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
+ if (dev->ctrl.admin_q)
+ blk_put_queue(dev->ctrl.admin_q);
+ kfree(dev->queues);
++#ifdef HAVE_LINUX_SED_OPAL_H
+ free_opal_dev(dev->ctrl.opal_dev);
++#endif
++#ifndef HAVE_PCI_IRQ_API
++ kfree(dev->entry);
++#endif
+ kfree(dev);
+ }
+
+@@ -2299,7 +2582,9 @@ static void nvme_reset_work(struct work_struct *work)
+ {
+ struct nvme_dev *dev =
+ container_of(work, struct nvme_dev, ctrl.reset_work);
++#ifdef HAVE_LINUX_SED_OPAL_H
+ bool was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL);
++#endif
+ int result = -ENODEV;
+ enum nvme_ctrl_state new_state = NVME_CTRL_LIVE;
+
+@@ -2339,6 +2624,7 @@ static void nvme_reset_work(struct work_struct *work)
+ if (result)
+ goto out;
+
++#ifdef HAVE_LINUX_SED_OPAL_H
+ if (dev->ctrl.oacs & NVME_CTRL_OACS_SEC_SUPP) {
+ if (!dev->ctrl.opal_dev)
+ dev->ctrl.opal_dev =
+@@ -2349,6 +2635,7 @@ static void nvme_reset_work(struct work_struct *work)
+ free_opal_dev(dev->ctrl.opal_dev);
+ dev->ctrl.opal_dev = NULL;
+ }
++#endif
+
+ if (dev->ctrl.oacs & NVME_CTRL_OACS_DBBUF_SUPP) {
+ result = nvme_dbbuf_dma_alloc(dev);
+@@ -2557,6 +2844,17 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ return result;
+ }
+
++#ifdef HAVE_PCI_ERROR_HANDLERS_RESET_NOTIFY
++static void nvme_reset_notify(struct pci_dev *pdev, bool prepare)
++{
++ struct nvme_dev *dev = pci_get_drvdata(pdev);
++
++ if (prepare)
++ nvme_dev_disable(dev, false);
++ else
++ nvme_reset_ctrl(&dev->ctrl);
++}
++#elif defined(HAVE_PCI_ERROR_HANDLERS_RESET_PREPARE) && defined(HAVE_PCI_ERROR_HANDLERS_RESET_DONE)
+ static void nvme_reset_prepare(struct pci_dev *pdev)
+ {
+ struct nvme_dev *dev = pci_get_drvdata(pdev);
+@@ -2568,6 +2866,7 @@ static void nvme_reset_done(struct pci_dev *pdev)
+ struct nvme_dev *dev = pci_get_drvdata(pdev);
+ nvme_reset_ctrl_sync(&dev->ctrl);
+ }
++#endif
+
+ static void nvme_shutdown(struct pci_dev *pdev)
+ {
+@@ -2692,11 +2991,16 @@ static const struct pci_error_handlers nvme_err_handler = {
+ .error_detected = nvme_error_detected,
+ .slot_reset = nvme_slot_reset,
+ .resume = nvme_error_resume,
++#ifdef HAVE_PCI_ERROR_HANDLERS_RESET_NOTIFY
++ .reset_notify = nvme_reset_notify,
++#elif defined(HAVE_PCI_ERROR_HANDLERS_RESET_PREPARE) && defined(HAVE_PCI_ERROR_HANDLERS_RESET_DONE)
+ .reset_prepare = nvme_reset_prepare,
+ .reset_done = nvme_reset_done,
++#endif /* HAVE_PCI_ERROR_HANDLERS_RESET_NOTIFY */
+ };
+
+ static const struct pci_device_id nvme_id_table[] = {
++#ifdef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
+ { PCI_VDEVICE(INTEL, 0x0953),
+ .driver_data = NVME_QUIRK_STRIPE_SIZE |
+ NVME_QUIRK_DEALLOCATE_ZEROES, },
+@@ -2709,6 +3013,17 @@ static const struct pci_device_id nvme_id_table[] = {
+ { PCI_VDEVICE(INTEL, 0x0a55),
+ .driver_data = NVME_QUIRK_STRIPE_SIZE |
+ NVME_QUIRK_DEALLOCATE_ZEROES, },
++#else
++ { PCI_VDEVICE(INTEL, 0x0953),
++ .driver_data = NVME_QUIRK_STRIPE_SIZE |
++ NVME_QUIRK_DISCARD_ZEROES, },
++ { PCI_VDEVICE(INTEL, 0x0a53),
++ .driver_data = NVME_QUIRK_STRIPE_SIZE |
++ NVME_QUIRK_DISCARD_ZEROES, },
++ { PCI_VDEVICE(INTEL, 0x0a54),
++ .driver_data = NVME_QUIRK_STRIPE_SIZE |
++ NVME_QUIRK_DISCARD_ZEROES, },
++#endif
+ { PCI_VDEVICE(INTEL, 0xf1a5), /* Intel 600P/P3100 */
+ .driver_data = NVME_QUIRK_NO_DEEPEST_PS |
+ NVME_QUIRK_MEDIUM_PRIO_SQ },
+diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/nvme/host/rdma.c
++++ b/drivers/nvme/host/rdma.c
+@@ -11,22 +11,32 @@
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <rdma/mr_pool.h>
+ #include <linux/err.h>
++#include <linux/sizes.h>
+ #include <linux/string.h>
+ #include <linux/atomic.h>
+ #include <linux/blk-mq.h>
++#ifdef HAVE_BLK_MQ_MAP_QUEUES
+ #include <linux/blk-mq-rdma.h>
++#endif
+ #include <linux/types.h>
+ #include <linux/list.h>
+ #include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+ #include <linux/nvme.h>
+ #include <asm/unaligned.h>
++#ifdef HAVE_SCSI_MAX_SG_SEGMENTS
++#include <scsi/scsi.h>
++#endif
++#include <linux/refcount.h>
+
+ #include <rdma/ib_verbs.h>
+ #include <rdma/rdma_cm.h>
+@@ -144,8 +154,13 @@ static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id,
+ struct rdma_cm_event *event);
+ static void nvme_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc);
+
++#ifdef HAVE_BLK_MQ_TAG_SET_HAS_CONST_POS
+ static const struct blk_mq_ops nvme_rdma_mq_ops;
+ static const struct blk_mq_ops nvme_rdma_admin_mq_ops;
++#else
++static struct blk_mq_ops nvme_rdma_mq_ops;
++static struct blk_mq_ops nvme_rdma_admin_mq_ops;
++#endif
+
+ /* XXX: really should move to a generic header sooner or later.. */
+ static inline void put_unaligned_le24(u32 val, u8 *p)
+@@ -261,26 +276,57 @@ static int nvme_rdma_create_qp(struct nvme_rdma_queue *queue, const int factor)
+ return ret;
+ }
+
++#ifdef HAVE_BLK_MQ_OPS_EXIT_REQUEST_HAS_3_PARAMS
+ static void nvme_rdma_exit_request(struct blk_mq_tag_set *set,
+ struct request *rq, unsigned int hctx_idx)
++#else
++static void __nvme_rdma_exit_request(struct nvme_rdma_ctrl *ctrl,
++ struct request *rq, unsigned int queue_idx)
++#endif
+ {
++#ifdef HAVE_BLK_MQ_OPS_EXIT_REQUEST_HAS_3_PARAMS
+ struct nvme_rdma_ctrl *ctrl = set->driver_data;
++#endif
+ struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
++#ifdef HAVE_BLK_MQ_OPS_EXIT_REQUEST_HAS_3_PARAMS
+ int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0;
++#endif
+ struct nvme_rdma_queue *queue = &ctrl->queues[queue_idx];
+ struct nvme_rdma_device *dev = queue->device;
+
+ nvme_rdma_free_qe(dev->dev, &req->sqe, sizeof(struct nvme_command),
+ DMA_TO_DEVICE);
+ }
++#ifndef HAVE_BLK_MQ_OPS_EXIT_REQUEST_HAS_3_PARAMS
++static void nvme_rdma_exit_request(void *data, struct request *rq,
++ unsigned int hctx_idx, unsigned int rq_idx)
++{
++ __nvme_rdma_exit_request(data, rq, hctx_idx + 1);
++}
++
++static void nvme_rdma_exit_admin_request(void *data, struct request *rq,
++ unsigned int hctx_idx, unsigned int rq_idx)
++{
++ __nvme_rdma_exit_request(data, rq, 0);
++}
++#endif
+
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ static int nvme_rdma_init_request(struct blk_mq_tag_set *set,
+ struct request *rq, unsigned int hctx_idx,
+ unsigned int numa_node)
++#else
++static int __nvme_rdma_init_request(struct nvme_rdma_ctrl *ctrl,
++ struct request *rq, unsigned int queue_idx)
++#endif
+ {
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ struct nvme_rdma_ctrl *ctrl = set->driver_data;
++#endif
+ struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0;
++#endif
+ struct nvme_rdma_queue *queue = &ctrl->queues[queue_idx];
+ struct nvme_rdma_device *dev = queue->device;
+ struct ib_device *ibdev = dev->dev;
+@@ -295,6 +341,21 @@ static int nvme_rdma_init_request(struct blk_mq_tag_set *set,
+
+ return 0;
+ }
++#ifndef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
++static int nvme_rdma_init_request(void *data, struct request *rq,
++ unsigned int hctx_idx, unsigned int rq_idx,
++ unsigned int numa_node)
++{
++ return __nvme_rdma_init_request(data, rq, hctx_idx + 1);
++}
++
++static int nvme_rdma_init_admin_request(void *data, struct request *rq,
++ unsigned int hctx_idx, unsigned int rq_idx,
++ unsigned int numa_node)
++{
++ return __nvme_rdma_init_request(data, rq, 0);
++}
++#endif
+
+ static int nvme_rdma_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
+ unsigned int hctx_idx)
+@@ -428,6 +489,9 @@ static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue)
+ const int cq_factor = send_wr_factor + 1; /* + RECV */
+ int comp_vector, idx = nvme_rdma_queue_idx(queue);
+ int ret;
++#ifndef HAVE_BLK_QUEUE_VIRT_BOUNDARY
++ enum ib_mr_type mr_type;
++#endif
+
+ queue->device = nvme_rdma_find_get_device(queue->cm_id);
+ if (!queue->device) {
+@@ -437,11 +501,15 @@ static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue)
+ }
+ ibdev = queue->device->dev;
+
++#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HCTX
+ /*
+ * Spread I/O queues completion vectors according their queue index.
+ * Admin queues can always go on completion vector 0.
+ */
+ comp_vector = idx == 0 ? idx : idx - 1;
++#else
++ comp_vector = queue->ctrl->ctrl.instance % ibdev->num_comp_vectors;
++#endif
+
+ /* +1 for ib_stop_cq */
+ queue->ib_cq = ib_alloc_cq(ibdev, queue,
+@@ -463,9 +531,20 @@ static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue)
+ goto out_destroy_qp;
+ }
+
++#ifndef HAVE_BLK_QUEUE_VIRT_BOUNDARY
++ if (ibdev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG)
++ mr_type = IB_MR_TYPE_SG_GAPS;
++ else
++ mr_type = IB_MR_TYPE_MEM_REG;
++#endif
++
+ ret = ib_mr_pool_init(queue->qp, &queue->qp->rdma_mrs,
+ queue->queue_size,
++#ifdef HAVE_BLK_QUEUE_VIRT_BOUNDARY
+ IB_MR_TYPE_MEM_REG,
++#else
++ mr_type,
++#endif
+ nvme_rdma_get_max_fr_pages(ibdev));
+ if (ret) {
+ dev_err(queue->ctrl->ctrl.device,
+@@ -688,12 +767,19 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
+ set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
+ set->reserved_tags = 2; /* connect + keep-alive */
+ set->numa_node = NUMA_NO_NODE;
++#ifdef HAVE_SCSI_MAX_SG_SEGMENTS
++ set->cmd_size = sizeof(struct nvme_rdma_request) +
++ SCSI_MAX_SG_SEGMENTS * sizeof(struct scatterlist);
++#else
+ set->cmd_size = sizeof(struct nvme_rdma_request) +
+ SG_CHUNK_SIZE * sizeof(struct scatterlist);
++#endif
+ set->driver_data = ctrl;
+ set->nr_hw_queues = 1;
+ set->timeout = ADMIN_TIMEOUT;
++#ifdef HAVE_BLK_MQ_F_NO_SCHED
+ set->flags = BLK_MQ_F_NO_SCHED;
++#endif
+ } else {
+ set = &ctrl->tag_set;
+ memset(set, 0, sizeof(*set));
+@@ -702,8 +788,13 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
+ set->reserved_tags = 1; /* fabric connect */
+ set->numa_node = NUMA_NO_NODE;
+ set->flags = BLK_MQ_F_SHOULD_MERGE;
++#ifdef HAVE_SCSI_MAX_SG_SEGMENTS
++ set->cmd_size = sizeof(struct nvme_rdma_request) +
++ SCSI_MAX_SG_SEGMENTS * sizeof(struct scatterlist);
++#else
+ set->cmd_size = sizeof(struct nvme_rdma_request) +
+ SG_CHUNK_SIZE * sizeof(struct scatterlist);
++#endif
+ set->driver_data = ctrl;
+ set->nr_hw_queues = nctrl->queue_count - 1;
+ set->timeout = NVME_IO_TIMEOUT;
+@@ -784,6 +875,10 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
+ ctrl->ctrl.sqsize =
+ min_t(int, NVME_CAP_MQES(ctrl->ctrl.cap), ctrl->ctrl.sqsize);
+
++#ifndef HAVE_BLK_QUEUE_VIRT_BOUNDARY
++ if (ctrl->device->dev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG)
++ ctrl->ctrl.sg_gaps_support = true;
++#endif
+ error = nvme_enable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap);
+ if (error)
+ goto out_cleanup_queue;
+@@ -846,8 +941,10 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
+ goto out_free_tag_set;
+ }
+ } else {
++#ifdef HAVE_BLK_MQ_UPDATE_NR_HW_QUEUES
+ blk_mq_update_nr_hw_queues(&ctrl->tag_set,
+ ctrl->ctrl.queue_count - 1);
++#endif
+ }
+
+ ret = nvme_rdma_start_io_queues(ctrl);
+@@ -968,7 +1065,11 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
+ nvme_rdma_destroy_io_queues(ctrl, false);
+ }
+
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_stop_hw_queues(ctrl->ctrl.admin_q);
++#endif
+ blk_mq_tagset_busy_iter(&ctrl->admin_tag_set,
+ nvme_cancel_request, &ctrl->ctrl);
+ nvme_rdma_destroy_admin_queue(ctrl, false);
+@@ -977,7 +1078,11 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
+ * queues are not a live anymore, so restart the queues to fail fast
+ * new IO
+ */
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(ctrl->ctrl.admin_q, true);
++#endif
+ nvme_start_queues(&ctrl->ctrl);
+
+ if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
+@@ -1058,7 +1163,11 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue,
+ struct nvme_rdma_device *dev = queue->device;
+ struct ib_device *ibdev = dev->dev;
+
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ if (!blk_rq_payload_bytes(rq))
++#else
++ if (!nvme_map_len(rq))
++#endif
+ return;
+
+ if (req->mr) {
+@@ -1173,12 +1282,23 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
+
+ c->common.flags |= NVME_CMD_SGL_METABUF;
+
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ if (!blk_rq_payload_bytes(rq))
++#else
++ if (!nvme_map_len(rq))
++#endif
+ return nvme_rdma_set_sg_null(c);
+
+ req->sg_table.sgl = req->first_sgl;
++#ifdef HAVE_SG_ALLOC_TABLE_CHAINED_4_PARAMS
++ ret = sg_alloc_table_chained(&req->sg_table,
++ blk_rq_nr_phys_segments(rq),
++ GFP_ATOMIC,
++ req->sg_table.sgl);
++#else
+ ret = sg_alloc_table_chained(&req->sg_table,
+ blk_rq_nr_phys_segments(rq), req->sg_table.sgl);
++#endif
+ if (ret)
+ return -ENOMEM;
+
+@@ -1193,7 +1313,11 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
+
+ if (count == 1) {
+ if (rq_data_dir(rq) == WRITE && nvme_rdma_queue_idx(queue) &&
++#ifdef HAVE_BLK_RQ_NR_PAYLOAD_BYTES
+ blk_rq_payload_bytes(rq) <=
++#else
++ nvme_map_len(rq) <=
++#endif
+ nvme_rdma_inline_data_size(queue))
+ return nvme_rdma_map_sg_inline(queue, req, c);
+
+@@ -1658,6 +1782,7 @@ err:
+ return BLK_STS_IOERR;
+ }
+
++#ifdef HAVE_BLK_MQ_POLL
+ static int nvme_rdma_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
+ {
+ struct nvme_rdma_queue *queue = hctx->driver_data;
+@@ -1678,6 +1803,7 @@ static int nvme_rdma_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
+
+ return found;
+ }
++#endif
+
+ static void nvme_rdma_complete_rq(struct request *rq)
+ {
+@@ -1687,29 +1813,51 @@ static void nvme_rdma_complete_rq(struct request *rq)
+ nvme_complete_rq(rq);
+ }
+
++#ifdef HAVE_BLK_MQ_MAP_QUEUES
+ static int nvme_rdma_map_queues(struct blk_mq_tag_set *set)
+ {
+ struct nvme_rdma_ctrl *ctrl = set->driver_data;
+
+ return blk_mq_rdma_map_queues(set, ctrl->device->dev, 0);
+ }
++#endif
+
++#ifdef HAVE_BLK_MQ_TAG_SET_HAS_CONST_POS
+ static const struct blk_mq_ops nvme_rdma_mq_ops = {
++#else
++static struct blk_mq_ops nvme_rdma_mq_ops = {
++#endif
+ .queue_rq = nvme_rdma_queue_rq,
+ .complete = nvme_rdma_complete_rq,
+ .init_request = nvme_rdma_init_request,
+ .exit_request = nvme_rdma_exit_request,
+ .init_hctx = nvme_rdma_init_hctx,
++#ifdef HAVE_BLK_MQ_POLL
+ .poll = nvme_rdma_poll,
++#endif
+ .timeout = nvme_rdma_timeout,
++#ifdef HAVE_BLK_MQ_MAP_QUEUES
+ .map_queues = nvme_rdma_map_queues,
++#endif
+ };
+
++#ifdef HAVE_BLK_MQ_TAG_SET_HAS_CONST_POS
+ static const struct blk_mq_ops nvme_rdma_admin_mq_ops = {
++#else
++static struct blk_mq_ops nvme_rdma_admin_mq_ops = {
++#endif
+ .queue_rq = nvme_rdma_queue_rq,
+ .complete = nvme_rdma_complete_rq,
++#ifdef HAVE_BLK_MQ_OPS_INIT_REQUEST_HAS_4_PARAMS
+ .init_request = nvme_rdma_init_request,
++#else
++ .init_request = nvme_rdma_init_admin_request,
++#endif
++#ifdef HAVE_BLK_MQ_OPS_EXIT_REQUEST_HAS_3_PARAMS
+ .exit_request = nvme_rdma_exit_request,
++#else
++ .exit_request = nvme_rdma_exit_admin_request,
++#endif
+ .init_hctx = nvme_rdma_init_admin_hctx,
+ .timeout = nvme_rdma_timeout,
+ };
+@@ -1728,10 +1876,18 @@ static void nvme_rdma_shutdown_ctrl(struct nvme_rdma_ctrl *ctrl, bool shutdown)
+ else
+ nvme_disable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap);
+
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_stop_hw_queues(ctrl->ctrl.admin_q);
++#endif
+ blk_mq_tagset_busy_iter(&ctrl->admin_tag_set,
+ nvme_cancel_request, &ctrl->ctrl);
++#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
+ blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
++#else
++ blk_mq_start_stopped_hw_queues(ctrl->ctrl.admin_q, true);
++#endif
+ nvme_rdma_destroy_admin_queue(ctrl, shutdown);
+ }
+
+diff --git a/include/linux/blk-mq-rdma.h b/include/linux/blk-mq-rdma.h
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/include/linux/blk-mq-rdma.h
++++ b/include/linux/blk-mq-rdma.h
+@@ -1,10 +1,15 @@
+ #ifndef _LINUX_BLK_MQ_RDMA_H
+ #define _LINUX_BLK_MQ_RDMA_H
+
++#include "../../compat/config.h"
++
++#ifdef HAVE_BLK_MQ_MAP_QUEUES
+ struct blk_mq_tag_set;
+ struct ib_device;
+
++#define blk_mq_rdma_map_queues LINUX_BACKPORT(blk_mq_rdma_map_queues)
+ int blk_mq_rdma_map_queues(struct blk_mq_tag_set *set,
+ struct ib_device *dev, int first_vec);
++#endif /* HAVE_BLK_MQ_MAP_QUEUES */
+
+ #endif /* _LINUX_BLK_MQ_RDMA_H */