From: Israel Rukshin <israelr@mellanox.com>
Subject: [PATCH] BACKPORT: drivers/nvme/host/core.c

Change-Id: Ibfcc74945c146fd22236672047f42ed7d3154fce
---
 drivers/nvme/host/core.c | 979 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 972 insertions(+), 7 deletions(-)

--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -6,7 +6,9 @@
 
 #include <linux/blkdev.h>
 #include <linux/blk-mq.h>
+#ifdef HAVE_BLK_INTEGRITY_H
 #include <linux/blk-integrity.h>
+#endif
 #include <linux/compat.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -16,10 +18,14 @@
 #include <linux/backing-dev.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>
+#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
 #include <linux/pm_qos.h>
+#endif
 #include <asm/unaligned.h>
 
 #include "nvme.h"
@@ -50,8 +56,13 @@ MODULE_PARM_DESC(max_retries, "max numbe
 
 static unsigned long default_ps_max_latency_us = 100000;
 module_param(default_ps_max_latency_us, ulong, 0644);
+#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
 MODULE_PARM_DESC(default_ps_max_latency_us,
 		 "max power saving latency for new devices; use PM QOS to change per device");
+#else
+MODULE_PARM_DESC(default_ps_max_latency_us,
+		 "max power saving latency for new devices [deprecated]");
+#endif
 
 static bool force_apst;
 module_param(force_apst, bool, 0644);
@@ -79,7 +90,11 @@ MODULE_PARM_DESC(apst_secondary_latency_
 
 static bool streams;
 module_param(streams, bool, 0644);
+#ifdef HAVE_BLK_MAX_WRITE_HINTS
 MODULE_PARM_DESC(streams, "turn on support for Streams write directives");
+#else
+MODULE_PARM_DESC(streams, "turn on support for Streams write directives [deprecated]");
+#endif
 
 /*
  * nvme_wq - hosts nvme related works that are not reset or delete
@@ -230,6 +245,7 @@ int nvme_delete_ctrl(struct nvme_ctrl *c
 }
 EXPORT_SYMBOL_GPL(nvme_delete_ctrl);
 
+#ifdef HAVE_DEVICE_REMOVE_FILE_SELF
 static void nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
 {
 	/*
@@ -241,6 +257,7 @@ static void nvme_delete_ctrl_sync(struct
 		nvme_do_delete_ctrl(ctrl);
 	nvme_put_ctrl(ctrl);
 }
+#endif
 
 static blk_status_t nvme_error_status(u16 status)
 {
@@ -275,12 +292,18 @@ static blk_status_t nvme_error_status(u1
 		return BLK_STS_NEXUS;
 	case NVME_SC_HOST_PATH_ERROR:
 		return BLK_STS_TRANSPORT;
+#ifdef HAVE_BLK_MQ_BLK_STS_ZONE_ACTIVE_RESOURCE
 	case NVME_SC_ZONE_TOO_MANY_ACTIVE:
 		return BLK_STS_ZONE_ACTIVE_RESOURCE;
 	case NVME_SC_ZONE_TOO_MANY_OPEN:
 		return BLK_STS_ZONE_OPEN_RESOURCE;
+#endif
 	default:
+#ifdef HAVE_BLK_MQ_END_REQUEST_TAKES_BLK_STATUS_T
 		return BLK_STS_IOERR;
+#else
+		return -EIO;
+#endif
 	}
 }
 
@@ -295,8 +318,16 @@ static void nvme_retry_req(struct reques
 		delay = nvme_req(req)->ctrl->crdt[crd - 1] * 100;
 
 	nvme_req(req)->retries++;
+#ifdef HAVE_BLK_MQ_REQUEUE_REQUEST_2_PARAMS
 	blk_mq_requeue_request(req, false);
+#else
+	blk_mq_requeue_request(req);
+#endif
+#ifdef HAVE_BLK_MQ_DELAY_KICK_REQUEUE_LIST
 	blk_mq_delay_kick_requeue_list(req->q, delay);
+#else
+	blk_mq_kick_requeue_list(req->q);
+#endif
 }
 
 enum nvme_disposition {
@@ -315,6 +346,7 @@ static inline enum nvme_disposition nvme
 	    nvme_req(req)->retries >= nvme_max_retries)
 		return COMPLETE;
 
+#ifdef CONFIG_NVME_MULTIPATH
 	if (req->cmd_flags & REQ_NVME_MPATH) {
 		if (nvme_is_path_error(nvme_req(req)->status) ||
 		    blk_queue_dying(req->q))
@@ -323,16 +355,22 @@ static inline enum nvme_disposition nvme
 		if (blk_queue_dying(req->q))
 			return COMPLETE;
 	}
+#else
+	if (blk_queue_dying(req->q))
+		return COMPLETE;
+#endif
 
 	return RETRY;
 }
 
 static inline void nvme_end_req_zoned(struct request *req)
 {
+#ifdef HAVE_BLK_QUEUE_MAX_ACTIVE_ZONES
 	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
 	    req_op(req) == REQ_OP_ZONE_APPEND)
 		req->__sector = nvme_lba_to_sect(req->q->queuedata,
 			le64_to_cpu(nvme_req(req)->result.u64));
+#endif
 }
 
 static inline void nvme_end_req(struct request *req)
@@ -340,7 +378,12 @@ static inline void nvme_end_req(struct r
 	blk_status_t status = nvme_error_status(nvme_req(req)->status);
 
 	nvme_end_req_zoned(req);
+#ifdef HAVE_TRACE_BLOCK_BIO_COMPLETE_2_PARAM
 	nvme_trace_bio_complete(req);
+#else
+	nvme_trace_bio_complete(req, status);
+
+#endif
 	blk_mq_end_request(req, status);
 }
 
@@ -383,25 +426,54 @@ EXPORT_SYMBOL_GPL(nvme_complete_batch_re
 blk_status_t nvme_host_path_error(struct request *req)
 {
 	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
+#ifdef HAVE_MQ_RQ_STATE
 	blk_mq_set_request_complete(req);
+#endif
 	nvme_complete_rq(req);
 	return BLK_STS_OK;
 }
 EXPORT_SYMBOL_GPL(nvme_host_path_error);
 
+#ifdef HAVE_BLK_MQ_BUSY_TAG_ITER_FN_BOOL_3_PARAMS
 bool nvme_cancel_request(struct request *req, void *data, bool reserved)
+#elif defined HAVE_BLK_MQ_BUSY_TAG_ITER_FN_BOOL_2_PARAMS
+bool nvme_cancel_request(struct request *req, void *data)
+#else
+void nvme_cancel_request(struct request *req, void *data, bool reserved)
+#endif
 {
+#ifndef HAVE_BLK_MQ_BUSY_TAG_ITER_FN_BOOL
+	if (!blk_mq_request_started(req))
+		return;
+#endif
+
 	dev_dbg_ratelimited(((struct nvme_ctrl *) data)->device,
 				"Cancelling I/O %d", req->tag);
 
+#ifdef HAVE_MQ_RQ_STATE
 	/* don't abort one completed request */
 	if (blk_mq_request_completed(req))
+#ifdef HAVE_BLK_MQ_BUSY_TAG_ITER_FN_BOOL
 		return true;
+#else
+		return;
+#endif
+#endif
 
 	nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
 	nvme_req(req)->flags |= NVME_REQ_CANCELLED;
+#ifdef HAVE_BLK_MQ_COMPLETE_REQUEST_HAS_2_PARAMS
+	blk_mq_complete_request(req, 0);
+#else
+#ifdef HAVE_BLK_MQ_COMPLETE_REQUEST_SYNC
+	blk_mq_complete_request_sync(req);
+#else
 	blk_mq_complete_request(req);
+#endif
+#endif
+#ifdef HAVE_BLK_MQ_BUSY_TAG_ITER_FN_BOOL
 	return true;
+#endif
 }
 EXPORT_SYMBOL_GPL(nvme_cancel_request);
 
@@ -425,6 +497,18 @@ void nvme_cancel_admin_tagset(struct nvm
 }
 EXPORT_SYMBOL_GPL(nvme_cancel_admin_tagset);
 
+#ifndef HAVE_BLKDEV_QUEUE_FLAG_QUIESCED
+void nvme_ns_kick_requeue_lists(struct nvme_ctrl *ctrl)
+{
+	struct nvme_ns *ns;
+
+	down_read(&ctrl->namespaces_rwsem);
+	list_for_each_entry(ns, &ctrl->namespaces, list)
+		blk_mq_kick_requeue_list(ns->queue);
+	up_read(&ctrl->namespaces_rwsem);
+}
+#endif
+
 bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
 		enum nvme_ctrl_state new_state)
 {
@@ -513,6 +597,9 @@ bool nvme_change_ctrl_state(struct nvme_
 	if (ctrl->state == NVME_CTRL_LIVE) {
 		if (old_state == NVME_CTRL_CONNECTING)
 			nvme_stop_failfast_work(ctrl);
+#ifndef HAVE_BLKDEV_QUEUE_FLAG_QUIESCED
+		nvme_ns_kick_requeue_lists(ctrl);
+#endif
 		nvme_kick_requeue_lists(ctrl);
 	} else if (ctrl->state == NVME_CTRL_CONNECTING &&
 		old_state == NVME_CTRL_RESETTING) {
@@ -604,13 +691,19 @@ static inline void nvme_clear_nvme_reque
 	nvme_req(req)->status = 0;
 	nvme_req(req)->retries = 0;
 	nvme_req(req)->flags = 0;
+#ifdef HAVE_REQUEST_RQ_FLAGS
 	req->rq_flags |= RQF_DONTPREP;
+#else
+	req->cmd_flags |= REQ_DONTPREP;
+#endif
 }
 
+#ifdef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
 static inline unsigned int nvme_req_op(struct nvme_command *cmd)
 {
 	return nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
 }
+#endif
 
 static inline void nvme_init_request(struct request *req,
 		struct nvme_command *cmd)
@@ -624,35 +717,81 @@ static inline void nvme_init_request(str
 	cmd->common.flags &= ~NVME_CMD_SGL_ALL;
 
 	req->cmd_flags |= REQ_FAILFAST_DRIVER;
+#ifdef HAVE_BLK_MQ_HCTX_TYPE
 	if (req->mq_hctx->type == HCTX_TYPE_POLL)
+#ifdef HAVE_BLK_TYPES_REQ_HIPRI
+		req->cmd_flags |= REQ_HIPRI;
+#else
 		req->cmd_flags |= REQ_POLLED;
+#endif
+#endif
 	nvme_clear_nvme_request(req);
 	memcpy(nvme_req(req)->cmd, cmd, sizeof(*cmd));
 }
 
+#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)
+#else
+struct request *nvme_alloc_request(struct request_queue *q,
+		struct nvme_command *cmd, gfp_t gfp, bool reserved)
+#endif
 {
 	struct request *req;
 
+#ifdef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
 	req = blk_mq_alloc_request(q, nvme_req_op(cmd), flags);
-	if (!IS_ERR(req))
+#else
+#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
+	req = blk_mq_alloc_request(q, nvme_is_write(cmd), flags);
+#else
+	// XXX RH 7.2 doesn't use qid.
+	// 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)) {
+#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
 		nvme_init_request(req, cmd);
+	}
+
 	return req;
 }
 EXPORT_SYMBOL_GPL(nvme_alloc_request);
 
+#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
 static struct request *nvme_alloc_request_qid(struct request_queue *q,
 		struct nvme_command *cmd, blk_mq_req_flags_t flags, int qid)
 {
 	struct request *req;
 
+#ifdef HAVE_BLK_TYPES_REQ_OP_DRV_OUT
 	req = blk_mq_alloc_request_hctx(q, nvme_req_op(cmd), flags,
 			qid ? qid - 1 : 0);
-	if (!IS_ERR(req))
+#else
+	req = blk_mq_alloc_request_hctx(q, nvme_is_write(cmd), flags,
+			qid ? qid - 1 : 0);
+#endif
+	if (!IS_ERR(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
 		nvme_init_request(req, cmd);
+	}
+
 	return req;
 }
+#endif
 
 /*
  * For something we're not in a state to send to the device the default action
@@ -666,12 +805,25 @@ static struct request *nvme_alloc_reques
 blk_status_t nvme_fail_nonready_command(struct nvme_ctrl *ctrl,
 		struct request *rq)
 {
+#ifdef CONFIG_NVME_MULTIPATH
 	if (ctrl->state != NVME_CTRL_DELETING_NOIO &&
 	    ctrl->state != NVME_CTRL_DELETING &&
 	    ctrl->state != NVME_CTRL_DEAD &&
 	    !test_bit(NVME_CTRL_FAILFAST_EXPIRED, &ctrl->flags) &&
 	    !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
+#else
+	if (ctrl->state != NVME_CTRL_DELETING_NOIO &&
+	    ctrl->state != NVME_CTRL_DELETING &&
+	    ctrl->state != NVME_CTRL_DEAD &&
+	    !test_bit(NVME_CTRL_FAILFAST_EXPIRED, &ctrl->flags) &&
+	    !blk_noretry_request(rq))
+#endif
 		return BLK_STS_RESOURCE;
+
+#ifndef HAVE_MQ_RQ_STATE
+	blk_mq_start_request(rq);
+#endif
+
 	return nvme_host_path_error(rq);
 }
 EXPORT_SYMBOL_GPL(nvme_fail_nonready_command);
@@ -715,6 +867,7 @@ bool __nvme_check_ready(struct nvme_ctrl
 }
 EXPORT_SYMBOL_GPL(__nvme_check_ready);
 
+#ifdef HAVE_BLK_MAX_WRITE_HINTS
 static int nvme_toggle_streams(struct nvme_ctrl *ctrl, bool enable)
 {
 	struct nvme_command c = { };
@@ -813,6 +966,7 @@ static void nvme_assign_write_stream(str
 	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)
@@ -825,16 +979,32 @@ static inline void nvme_setup_flush(stru
 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;
+#else
+	unsigned short segments = 1;
+#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
 
 	/*
 	 * Some devices do not consider the DSM 'Number of Ranges' field when
 	 * determining how much data to DMA. Always allocate memory for maximum
 	 * number of segments to prevent device reading beyond end of buffer.
 	 */
+#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
 	static const size_t alloc_size = sizeof(*range) * NVME_DSM_MAX_RANGES;
+#else
+	static const size_t alloc_size = sizeof(*range);
+#endif
 
 	range = kzalloc(alloc_size, GFP_ATOMIC | __GFP_NOWARN);
 	if (!range) {
@@ -849,6 +1019,7 @@ static blk_status_t nvme_setup_discard(s
 		range = page_address(ns->ctrl->discard_page);
 	}
 
+#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
 	__rq_for_each_bio(bio, req) {
 		u64 slba = nvme_sect_to_lba(ns, bio->bi_iter.bi_sector);
 		u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift;
@@ -868,6 +1039,11 @@ static blk_status_t nvme_setup_discard(s
 			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_sect_to_lba(ns, blk_rq_pos(req)));
+#endif
 
 	memset(cmnd, 0, sizeof(*cmnd));
 	cmnd->dsm.opcode = nvme_cmd_dsm;
@@ -875,10 +1051,29 @@ static blk_status_t nvme_setup_discard(s
 	cmnd->dsm.nr = cpu_to_le32(segments - 1);
 	cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD);
 
+#ifdef HAVE_REQUEST_RQ_FLAGS
 	req->special_vec.bv_page = virt_to_page(range);
 	req->special_vec.bv_offset = offset_in_page(range);
 	req->special_vec.bv_len = alloc_size;
 	req->rq_flags |= RQF_SPECIAL_PAYLOAD;
+#else
+	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;
+#endif /* HAVE_REQUEST_RQ_FLAGS */
 
 	return BLK_STS_OK;
 }
@@ -888,8 +1083,10 @@ static inline blk_status_t nvme_setup_wr
 {
 	memset(cmnd, 0, sizeof(*cmnd));
 
+#ifdef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
 	if (ns->ctrl->quirks & NVME_QUIRK_DEALLOCATE_ZEROES)
 		return nvme_setup_discard(ns, req, cmnd);
+#endif
 
 	cmnd->write_zeroes.opcode = nvme_cmd_write_zeroes;
 	cmnd->write_zeroes.nsid = cpu_to_le32(ns->head->ns_id);
@@ -917,7 +1114,9 @@ static inline blk_status_t nvme_setup_rw
 		struct request *req, struct nvme_command *cmnd,
 		enum nvme_opcode op)
 {
+#ifdef HAVE_BLK_MAX_WRITE_HINTS
 	struct nvme_ctrl *ctrl = ns->ctrl;
+#endif
 	u16 control = 0;
 	u32 dsmgmt = 0;
 
@@ -940,8 +1139,10 @@ static inline blk_status_t nvme_setup_rw
 	cmnd->rw.apptag = 0;
 	cmnd->rw.appmask = 0;
 
+#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) {
 		/*
@@ -954,6 +1155,14 @@ static inline blk_status_t nvme_setup_rw
 			if (WARN_ON_ONCE(!nvme_ns_has_pi(ns)))
 				return BLK_STS_NOTSUPP;
 			control |= NVME_RW_PRINFO_PRACT;
+#if defined(HAVE_T10_PI_PREPARE) || !defined(HAVE_T10_PI_H)
+#ifdef HAVE_REQ_OP
+		} else if (req_op(req) == REQ_OP_WRITE) {
+#else
+		} else if (rq_data_dir(req) == WRITE) {
+#endif
+			t10_pi_prepare(req, ns->pi_type);
+#endif
 		}
 
 		switch (ns->pi_type) {
@@ -978,14 +1187,46 @@ static inline blk_status_t nvme_setup_rw
 
 void nvme_cleanup_cmd(struct request *req)
 {
+#if defined(HAVE_T10_PI_PREPARE) || !defined(HAVE_T10_PI_H)
+#ifdef HAVE_REQ_OP
+	if (blk_integrity_rq(req) && req_op(req) == REQ_OP_READ &&
+	    nvme_req(req)->status == 0) {
+#else
+	if (blk_integrity_rq(req) && rq_data_dir(req) == READ &&
+	nvme_req(req)->status == 0) {
+#endif
+		struct nvme_ns *ns = req->rq_disk->private_data;
+
+		t10_pi_complete(req, ns->pi_type,
+				 blk_rq_bytes(req) >> ns->lba_shift);
+	}
+#endif
+#ifdef HAVE_REQUEST_RQ_FLAGS
 	if (req->rq_flags & RQF_SPECIAL_PAYLOAD) {
 		struct nvme_ctrl *ctrl = nvme_req(req)->ctrl;
+#ifdef HAVE_BVEC_VIRT
 
 		if (req->special_vec.bv_page == ctrl->discard_page)
 			clear_bit_unlock(0, &ctrl->discard_page_busy);
 		else
 			kfree(bvec_virt(&req->special_vec));
+#else
+		struct page *page = req->special_vec.bv_page;
+
+		if (page == ctrl->discard_page)
+			clear_bit_unlock(0, &ctrl->discard_page_busy);
+		else
+			kfree(page_address(page) + req->special_vec.bv_offset);
+#endif
 	}
+#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
 }
 EXPORT_SYMBOL_GPL(nvme_cleanup_cmd);
 
@@ -994,9 +1235,14 @@ blk_status_t nvme_setup_cmd(struct nvme_
 	struct nvme_command *cmd = nvme_req(req)->cmd;
 	blk_status_t ret = BLK_STS_OK;
 
+#ifdef HAVE_REQUEST_RQ_FLAGS
 	if (!(req->rq_flags & RQF_DONTPREP))
+#else
+	if (!(req->cmd_flags & REQ_DONTPREP))
+#endif
 		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:
@@ -1005,6 +1251,7 @@ blk_status_t nvme_setup_cmd(struct nvme_
 	case REQ_OP_FLUSH:
 		nvme_setup_flush(ns, cmd);
 		break;
+#ifdef HAVE_BLK_QUEUE_MAX_ACTIVE_ZONES
 	case REQ_OP_ZONE_RESET_ALL:
 	case REQ_OP_ZONE_RESET:
 		ret = nvme_setup_zone_mgmt_send(ns, req, cmd, NVME_ZONE_RESET);
@@ -1018,9 +1265,12 @@ blk_status_t nvme_setup_cmd(struct nvme_
 	case REQ_OP_ZONE_FINISH:
 		ret = nvme_setup_zone_mgmt_send(ns, req, cmd, NVME_ZONE_FINISH);
 		break;
+#endif
+#ifdef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
 	case REQ_OP_WRITE_ZEROES:
 		ret = nvme_setup_write_zeroes(ns, req, cmd);
 		break;
+#endif
 	case REQ_OP_DISCARD:
 		ret = nvme_setup_discard(ns, req, cmd);
 		break;
@@ -1030,13 +1280,43 @@ blk_status_t nvme_setup_cmd(struct nvme_
 	case REQ_OP_WRITE:
 		ret = nvme_setup_rw(ns, req, cmd, nvme_cmd_write);
 		break;
+#ifdef HAVE_BLK_QUEUE_MAX_ACTIVE_ZONES
 	case REQ_OP_ZONE_APPEND:
 		ret = nvme_setup_rw(ns, req, cmd, nvme_cmd_zone_append);
 		break;
+#endif
 	default:
 		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);
+#ifdef HAVE_REQ_OP
+	else if (req_op(req) == REQ_OP_READ)
+#else
+	else if (rq_data_dir(req) == READ)
+#endif
+		nvme_setup_rw(ns, req, cmd, nvme_cmd_read);
+	else
+		nvme_setup_rw(ns, req, cmd, nvme_cmd_write);
+#endif
 
 	cmd->common.command_id = nvme_cid(req);
 	trace_nvme_setup_cmd(req, cmd);
@@ -1050,35 +1330,52 @@ EXPORT_SYMBOL_GPL(nvme_setup_cmd);
  * >0: nvme controller's cqe status response
  * <0: kernel error in lieu of controller response
  */
+#if defined(HAVE_BLK_EXECUTE_RQ_2_PARAM) || defined(HAVE_BLK_EXECUTE_RQ_3_PARAM)
 static int nvme_execute_rq(struct gendisk *disk, struct request *rq,
 		bool at_head)
 {
 	blk_status_t status;
 
+#ifdef HAVE_BLK_EXECUTE_RQ_2_PARAM
 	status = blk_execute_rq(rq, at_head);
+#else
+	status = blk_execute_rq(disk, rq, at_head);
+#endif
 	if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
 		return -EINTR;
 	if (nvme_req(rq)->status)
 		return nvme_req(rq)->status;
 	return blk_status_to_errno(status);
 }
+#endif
 
 /*
  * 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,
+		bool poll)
+#endif
 {
 	struct request *req;
 	int ret;
 
+#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
 	if (qid == NVME_QID_ANY)
 		req = nvme_alloc_request(q, cmd, flags);
 	else
 		req = nvme_alloc_request_qid(q, cmd, flags, qid);
+#else
+	req = nvme_alloc_request(q, cmd, gfp, reserved);
+#endif
 	if (IS_ERR(req))
 		return PTR_ERR(req);
 
@@ -1091,9 +1388,23 @@ int __nvme_submit_sync_cmd(struct reques
 			goto out;
 	}
 
+#if defined(HAVE_BLK_EXECUTE_RQ_2_PARAM) || defined(HAVE_BLK_EXECUTE_RQ_3_PARAM)
 	ret = nvme_execute_rq(NULL, req, at_head);
 	if (result && ret >= 0)
 		*result = nvme_req(req)->result;
+#else
+#ifdef HAVE_BLK_EXECUTE_RQ_4_PARAM
+	blk_execute_rq(req->q, NULL, req, at_head);
+#else
+	blk_execute_rq(NULL, req, at_head);
+#endif
+	if (result)
+		*result = nvme_req(req)->result;
+	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
+		ret = -EINTR;
+	else
+		ret = nvme_req(req)->status;
+#endif
  out:
 	blk_mq_free_request(req);
 	return ret;
@@ -1103,8 +1414,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, false);
+#endif
 }
 EXPORT_SYMBOL_GPL(nvme_submit_sync_cmd);
 
@@ -1202,6 +1518,7 @@ static void nvme_passthru_end(struct nvm
 	}
 }
 
+#if defined(HAVE_BLK_EXECUTE_RQ_2_PARAM) || defined(HAVE_BLK_EXECUTE_RQ_3_PARAM)
 int nvme_execute_passthru_rq(struct request *rq)
 {
 	struct nvme_command *cmd = nvme_req(rq)->cmd;
@@ -1218,6 +1535,25 @@ int nvme_execute_passthru_rq(struct requ
 
 	return ret;
 }
+#else
+void nvme_execute_passthru_rq(struct request *rq)
+{
+	struct nvme_command *cmd = nvme_req(rq)->cmd;
+	struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl;
+	struct nvme_ns *ns = rq->q->queuedata;
+	struct gendisk *disk = ns ? ns->disk : NULL;
+	u32 effects;
+
+	effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
+#ifdef HAVE_BLK_EXECUTE_RQ_4_PARAM
+	blk_execute_rq(rq->q, disk, rq, 0);
+#else
+	blk_execute_rq(disk, rq, 0);
+#endif
+	if (effects) /* nothing to be done for zero cmd effects */
+		nvme_passthru_end(ctrl, effects, cmd, 0);
+}
+#endif
 EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU);
 
 /*
@@ -1231,7 +1567,11 @@ static void nvme_queue_keep_alive_work(s
 	queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ / 2);
 }
 
+#ifdef HAVE_RQ_END_IO_RET
+static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq, blk_status_t status)
+#else
 static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status)
+#endif
 {
 	struct nvme_ctrl *ctrl = rq->end_io_data;
 	unsigned long flags;
@@ -1243,7 +1583,11 @@ static void nvme_keep_alive_end_io(struc
 		dev_err(ctrl->device,
 			"failed nvme_keep_alive_end_io error=%d\n",
 				status);
+#ifdef HAVE_RQ_END_IO_RET
+		return RQ_END_IO_NONE;
+#else
 		return;
+#endif
 	}
 
 	ctrl->comp_seen = false;
@@ -1254,6 +1598,10 @@ static void nvme_keep_alive_end_io(struc
 	spin_unlock_irqrestore(&ctrl->lock, flags);
 	if (startka)
 		nvme_queue_keep_alive_work(ctrl);
+
+#ifdef HAVE_RQ_END_IO_RET
+	return RQ_END_IO_NONE;
+#endif
 }
 
 static void nvme_keep_alive_work(struct work_struct *work)
@@ -1270,9 +1618,12 @@ static void nvme_keep_alive_work(struct
 		nvme_queue_keep_alive_work(ctrl);
 		return;
 	}
-
+#ifdef HAVE_BLK_MQ_ALLOC_REQUEST_HAS_3_PARAMS
 	rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd,
 				BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
+#else
+	rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd, GFP_KERNEL, true);
+#endif
 	if (IS_ERR(rq)) {
 		/* allocation failure, reset the controller */
 		dev_err(ctrl->device, "keep-alive failed: %ld\n", PTR_ERR(rq));
@@ -1282,7 +1633,20 @@ static void nvme_keep_alive_work(struct
 
 	rq->timeout = ctrl->kato * HZ;
 	rq->end_io_data = ctrl;
+#ifdef HAVE_BLK_EXECUTE_RQ_NOWAIT_2_PARAM
+	rq->end_io = nvme_keep_alive_end_io;
+	blk_execute_rq_nowait(rq, false);
+#else
+#ifdef HAVE_BLK_EXECUTE_RQ_NOWAIT_5_PARAM
+	blk_execute_rq_nowait(rq->q, NULL, rq, 0, nvme_keep_alive_end_io);
+#else
+#ifdef HAVE_BLK_EXECUTE_RQ_NOWAIT_3_PARAM
 	blk_execute_rq_nowait(rq, false, nvme_keep_alive_end_io);
+#else
+	blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
+#endif
+#endif
+#endif
 }
 
 static void nvme_start_keep_alive(struct nvme_ctrl *ctrl)
@@ -1512,8 +1876,13 @@ static int nvme_features(struct nvme_ctr
 	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, false);
+#endif
 	if (ret >= 0 && result)
 		*result = le32_to_cpu(res.u32);
 	return ret;
@@ -1612,12 +1981,24 @@ static void nvme_ns_release(struct nvme_
 	nvme_put_ns(ns);
 }
 
+#ifdef HAVE_GENDISK_OPEN_MODE
+static int nvme_open(struct gendisk *disk, blk_mode_t mode)
+#else
 static int nvme_open(struct block_device *bdev, fmode_t mode)
+#endif
 {
+#ifdef HAVE_GENDISK_OPEN_MODE
+	return nvme_ns_open(disk->private_data);
+#else
 	return nvme_ns_open(bdev->bd_disk->private_data);
+#endif
 }
 
+#ifdef HAVE_GENDISK_OPEN_MODE
+static void nvme_release(struct gendisk *disk)
+#else
 static void nvme_release(struct gendisk *disk, fmode_t mode)
+#endif
 {
 	nvme_ns_release(disk->private_data);
 }
@@ -1632,6 +2013,7 @@ int nvme_getgeo(struct block_device *bde
 }
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
+#ifdef HAVE_BLK_INTEGRITY_DEVICE_CAPABLE
 static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
 				u32 max_integrity_segments)
 {
@@ -1658,6 +2040,47 @@ static void nvme_init_integrity(struct g
 	blk_queue_max_integrity_segments(disk->queue, max_integrity_segments);
 }
 #else
+#ifdef HAVE_REQUEST_QUEUE_INTEGRITY
+static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
+				u32 max_integrity_segments)
+{
+	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, max_integrity_segments);
+}
+#else
+static int nvme_noop_verify(struct blk_integrity_exchg *exg)
+{
+        return 0;
+}
+
+static void nvme_noop_generate(struct blk_integrity_exchg *exg)
+{
+}
+
+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 gendisk *disk, u16 ms, u8 pi_type,
+				u32 max_integrity_segments)
+{
+	nvme_meta_noop.tag_size = pi_type ? sizeof(u16) + sizeof(u32)
+					: sizeof(u16);
+	nvme_meta_noop.tuple_size = ms;
+	blk_integrity_register(disk, &nvme_meta_noop);
+	blk_queue_max_integrity_segments(disk->queue, max_integrity_segments);
+}
+#endif /* HAVE_REQUEST_QUEUE_INTEGRITY */
+#endif /* HAVE_BLK_INTEGRITY_DEVICE_CAPABLE */
+#else
 static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
 				u32 max_integrity_segments)
 {
@@ -1671,28 +2094,51 @@ static void nvme_config_discard(struct g
 	u32 size = queue_logical_block_size(queue);
 
 	if (ctrl->max_discard_sectors == 0) {
+#ifdef HAVE_QUEUE_FLAG_DISCARD
 		blk_queue_flag_clear(QUEUE_FLAG_DISCARD, queue);
+#else
+		blk_queue_max_discard_sectors(queue, 0);
+#endif
 		return;
 	}
 
+#ifdef HAVE_BLK_MAX_WRITE_HINTS
 	if (ctrl->nr_streams && ns->sws && ns->sgs)
 		size *= ns->sws * ns->sgs;
+#endif
 
+#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
 	BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) <
 			NVME_DSM_MAX_RANGES);
+#endif
+
+#ifndef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
+	if (ctrl->quirks & NVME_QUIRK_DISCARD_ZEROES)
+		queue->limits.discard_zeroes_data = 1;
+	else
+		queue->limits.discard_zeroes_data = 0;
+#endif
 
 	queue->limits.discard_alignment = 0;
 	queue->limits.discard_granularity = size;
 
 	/* If discard is already enabled, don't reset queue limits */
+#ifdef HAVE_QUEUE_FLAG_DISCARD
 	if (blk_queue_flag_test_and_set(QUEUE_FLAG_DISCARD, queue))
+#else
+	if (queue->limits.max_discard_sectors)
+#endif
 		return;
 
 	blk_queue_max_discard_sectors(queue, ctrl->max_discard_sectors);
+#ifdef HAVE_BLK_RQ_NR_DISCARD_SEGMENTS
 	blk_queue_max_discard_segments(queue, ctrl->max_discard_segments);
+#endif
 
+#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 bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b)
@@ -1703,6 +2149,7 @@ static bool nvme_ns_ids_equal(struct nvm
 		a->csi == b->csi;
 }
 
+#ifdef HAVE_BLK_MAX_WRITE_HINTS
 static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 				 u32 *phys_bs, u32 *io_opt)
 {
@@ -1727,7 +2174,9 @@ static int nvme_setup_streams_ns(struct
 
 	return 0;
 }
+#endif
 
+#if !defined HAVE_BD_SET_NR_SECTORS && !defined HAVE_BD_SET_SIZE && !defined HAVE_REVALIDATE_DISK_SIZE
 static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
 {
 	struct nvme_ctrl *ctrl = ns->ctrl;
@@ -1781,6 +2230,7 @@ static void nvme_configure_metadata(stru
 			ns->features |= NVME_NS_METADATA_SUPPORTED;
 	}
 }
+#endif
 
 static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
 		struct request_queue *q)
@@ -1795,7 +2245,12 @@ static void nvme_set_queue_limits(struct
 		blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors);
 		blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX));
 	}
+#ifdef HAVE_BLK_QUEUE_VIRT_BOUNDARY
 	blk_queue_virt_boundary(q, NVME_CTRL_PAGE_SIZE - 1);
+#else
+	if (!ctrl->sg_gaps_support)
+		queue_flag_set_unlocked(QUEUE_FLAG_SG_GAPS, q);
+#endif
 	blk_queue_dma_alignment(q, 3);
 	blk_queue_write_cache(q, vwc, vwc);
 }
@@ -1819,7 +2274,9 @@ static void nvme_update_disk_info(struct
 	blk_integrity_unregister(disk);
 
 	atomic_bs = phys_bs = bs;
+#ifdef HAVE_BLK_MAX_WRITE_HINTS
 	nvme_setup_streams_ns(ns->ctrl, ns, &phys_bs, &io_opt);
+#endif
 	if (id->nabo == 0) {
 		/*
 		 * Bit 1 indicates whether NAWUPF is defined for this namespace
@@ -1864,17 +2321,31 @@ static void nvme_update_disk_info(struct
 			capacity = 0;
 	}
 
+#if defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE
+#ifdef HAVE_SET_CAPACITY_REVALIDATE_AND_NOTIFY
+	set_capacity_revalidate_and_notify(disk, capacity, false);
+#else
+	set_capacity(disk, capacity);
+#endif
+#else
 	set_capacity_and_notify(disk, capacity);
+#endif
 
 	nvme_config_discard(disk, ns);
+#ifdef HAVE_BLK_QUEUE_MAX_WRITE_ZEROES_SECTORS
 	blk_queue_max_write_zeroes_sectors(disk->queue,
 					   ns->ctrl->max_zeroes_sectors);
+#endif
 }
 
 static inline bool nvme_first_scan(struct gendisk *disk)
 {
 	/* nvme_alloc_ns() scans the disk prior to adding it */
+#ifdef HAVE_GENHD_FL_UP
+	return !(disk->flags & GENHD_FL_UP);
+#else
 	return !disk_live(disk);
+#endif
 }
 
 static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
@@ -1898,16 +2369,190 @@ static void nvme_set_chunk_sectors(struc
 		return;
 	}
 
+#ifdef CONFIG_BLK_DEV_ZONED
 	if (blk_queue_is_zoned(ns->disk->queue)) {
 		if (nvme_first_scan(ns->disk))
 			pr_warn("%s: ignoring zoned namespace IO boundary\n",
 				ns->disk->disk_name);
 		return;
 	}
+#endif
 
 	blk_queue_chunk_sectors(ns->queue, iob);
 }
 
+#if defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE || defined HAVE_REVALIDATE_DISK_SIZE
+static void nvme_update_bdev_size(struct gendisk *disk);
+
+static int nvme_report_ns_ids(struct nvme_ctrl *ctrl, unsigned int nsid,
+		struct nvme_id_ns *id, struct nvme_ns_ids *ids)
+{
+	memset(ids, 0, sizeof(*ids));
+
+	if (ctrl->vs >= NVME_VS(1, 1, 0))
+		memcpy(ids->eui64, id->eui64, sizeof(id->eui64));
+	if (ctrl->vs >= NVME_VS(1, 2, 0))
+		memcpy(ids->nguid, id->nguid, sizeof(id->nguid));
+	if (ctrl->vs >= NVME_VS(1, 3, 0) || nvme_multi_css(ctrl))
+		return nvme_identify_ns_descs(ctrl, nsid, ids);
+	return 0;
+}
+
+
+static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
+{
+	unsigned lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
+	struct nvme_ns *ns = disk->private_data;
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	int ret;
+
+	/*
+	 * If identify namespace failed, use default 512 byte block size so
+	 * block layer can use before failing read/write for 0 capacity.
+	 */
+	ns->lba_shift = id->lbaf[lbaf].ds;
+	if (ns->lba_shift == 0)
+		ns->lba_shift = 9;
+
+	ns->noiob = le16_to_cpu(id->noiob);
+
+	switch (ns->head->ids.csi) {
+	case NVME_CSI_NVM:
+		break;
+	case NVME_CSI_ZNS:
+		ret = nvme_update_zone_info(ns, lbaf);
+		if (ret) {
+			dev_warn(ctrl->device,
+				"failed to add zoned namespace:%u ret:%d\n",
+				ns->head->ns_id, ret);
+			return ret;
+		}
+		break;
+	default:
+		dev_warn(ctrl->device, "unknown csi:%u ns:%u\n",
+			ns->head->ids.csi, ns->head->ns_id);
+		return -ENODEV;
+	}
+
+	ns->features = 0;
+	ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
+	/* the PI implementation requires metadata equal t10 pi tuple size */
+	if (ns->ms == sizeof(struct t10_pi_tuple))
+		ns->pi_type = id->dps & NVME_NS_DPS_PI_MASK;
+	else
+		ns->pi_type = 0;
+
+	if (ns->ms) {
+		/*
+		 * For PCIe only the separate metadata pointer is supported,
+		 * as the block layer supplies metadata in a separate bio_vec
+		 * chain. For Fabrics, only metadata as part of extended data
+		 * LBA is supported on the wire per the Fabrics specification,
+		 * but the HBA/HCA will do the remapping from the separate
+		 * metadata buffers for us.
+		 */
+		if (id->flbas & NVME_NS_FLBAS_META_EXT) {
+			ns->features |= NVME_NS_EXT_LBAS;
+			if ((ctrl->ops->flags & NVME_F_FABRICS) &&
+			    (ctrl->ops->flags & NVME_F_METADATA_SUPPORTED) &&
+			    ctrl->max_integrity_segments)
+				ns->features |= NVME_NS_METADATA_SUPPORTED;
+		} else {
+			if (WARN_ON_ONCE(ctrl->ops->flags & NVME_F_FABRICS))
+				return -EINVAL;
+			if (ctrl->ops->flags & NVME_F_METADATA_SUPPORTED)
+				ns->features |= NVME_NS_METADATA_SUPPORTED;
+		}
+	}
+
+	nvme_set_chunk_sectors(ns, id);
+	nvme_update_disk_info(disk, ns, id);
+	set_bit(NVME_NS_READY, &ns->flags);
+#ifdef CONFIG_NVME_MULTIPATH
+	if (ns->head->disk) {
+		nvme_update_disk_info(ns->head->disk, ns, id);
+		blk_stack_limits(&ns->head->disk->queue->limits,
+				 &ns->queue->limits, 0);
+#if defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE
+		nvme_update_bdev_size(ns->head->disk);
+#endif
+	}
+#endif
+	return 0;
+}
+
+static int _nvme_revalidate_disk(struct gendisk *disk)
+{
+	struct nvme_ns *ns = disk->private_data;
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	struct nvme_id_ns *id;
+	struct nvme_ns_ids ids;
+	int ret = 0;
+
+	if (test_bit(NVME_NS_DEAD, &ns->flags)) {
+		set_capacity(disk, 0);
+		return -ENODEV;
+	}
+
+	ret = nvme_identify_ns(ctrl, ns->head->ns_id, &ids, &id);
+	if (ret)
+		goto out;
+
+	if (id->ncap == 0) {
+		ret = -ENODEV;
+		goto free_id;
+	}
+
+	ret = nvme_report_ns_ids(ctrl, ns->head->ns_id, id, &ids);
+	if (ret)
+		goto free_id;
+
+	if (!nvme_ns_ids_equal(&ns->head->ids, &ids)) {
+		dev_err(ctrl->device,
+			"identifiers changed for nsid %d\n", ns->head->ns_id);
+		ret = -ENODEV;
+		goto free_id;
+	}
+
+	ret = __nvme_revalidate_disk(disk, id);
+free_id:
+	kfree(id);
+out:
+	/*
+	 * Only fail the function if we got a fatal error back from the
+	 * device, otherwise ignore the error and just move on.
+	 */
+	if (ret == -ENOMEM || (ret > 0 && !(ret & NVME_SC_DNR)))
+		ret = 0;
+	else if (ret > 0)
+		ret = blk_status_to_errno(nvme_error_status(ret));
+	return ret;
+}
+
+
+static int nvme_revalidate_disk(struct gendisk *disk)
+{
+	int ret;
+
+	ret = _nvme_revalidate_disk(disk);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_BLK_DEV_ZONED
+	if (blk_queue_is_zoned(disk->queue)) {
+		struct nvme_ns *ns = disk->private_data;
+		struct nvme_ctrl *ctrl = ns->ctrl;
+
+		ret = blk_revalidate_disk_zones(disk, NULL);
+		if (!ret)
+			blk_queue_max_zone_append_sectors(disk->queue,
+							  ctrl->max_zone_append);
+	}
+#endif
+	return ret;
+}
+#else //defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE || defined HAVE_REVALIDATE_DISK_SIZE
+
 static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
 {
 	unsigned lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
@@ -1935,11 +2580,13 @@ static int nvme_update_ns_info(struct nv
 	set_bit(NVME_NS_READY, &ns->flags);
 	blk_mq_unfreeze_queue(ns->disk->queue);
 
+#ifdef CONFIG_BLK_DEV_ZONED
 	if (blk_queue_is_zoned(ns->queue)) {
 		ret = nvme_revalidate_zones(ns);
 		if (ret && !nvme_first_scan(ns->disk))
 			goto out;
 	}
+#endif
 
 	if (nvme_ns_head_multipath(ns->head)) {
 		blk_mq_freeze_queue(ns->head->disk->queue);
@@ -1950,7 +2597,11 @@ static int nvme_update_ns_info(struct nv
 		nvme_mpath_revalidate_paths(ns);
 		blk_stack_limits(&ns->head->disk->queue->limits,
 				 &ns->queue->limits, 0);
+#ifdef HAVE_DISK_UPDATE_READAHEAD
 		disk_update_readahead(ns->head->disk);
+#else
+		blk_queue_update_readahead(ns->head->disk->queue);
+#endif
 		blk_mq_unfreeze_queue(ns->head->disk->queue);
 	}
 
@@ -1967,7 +2618,9 @@ out:
 	}
 	return ret;
 }
+#endif //defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE || defined HAVE_REVALIDATE_DISK_SIZE
 
+#ifdef HAVE_PR_H
 static char nvme_pr_type(enum pr_type type)
 {
 	switch (type) {
@@ -2085,7 +2738,9 @@ 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)
@@ -2101,11 +2756,18 @@ int nvme_sec_submit(void *data, u16 spsp
 	cmd.common.cdw10 = cpu_to_le32(((u32)secp) << 24 | ((u32)spsp) << 8);
 	cmd.common.cdw11 = 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, 0,
 			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, false);
+#endif
 }
 EXPORT_SYMBOL_GPL(nvme_sec_submit);
 #endif /* CONFIG_BLK_SED_OPAL */
+#endif /* HAVE_LINUX_SED_OPAL_H */
 
 #ifdef CONFIG_BLK_DEV_ZONED
 static int nvme_report_zones(struct gendisk *disk, sector_t sector,
@@ -2124,8 +2786,15 @@ static const struct block_device_operati
 	.open		= nvme_open,
 	.release	= nvme_release,
 	.getgeo		= nvme_getgeo,
+#ifdef HAVE_BLK_QUEUE_MAX_ACTIVE_ZONES
 	.report_zones	= nvme_report_zones,
+#endif
+#if !defined(HAVE_REVALIDATE_DISK_SIZE) && !defined(HAVE_BDEV_NR_SECTORS)
+	.revalidate_disk= nvme_revalidate_disk,
+#endif
+#ifdef HAVE_PR_H
 	.pr_ops		= &nvme_pr_ops,
+#endif
 };
 
 static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled)
@@ -2302,6 +2971,7 @@ static int nvme_configure_acre(struct nv
  * timeout value is returned and the matching tolerance index (1 or 2) is
  * reported.
  */
+#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
 static bool nvme_apst_get_transition_time(u64 total_latency,
 		u64 *transition_time, unsigned *last_index)
 {
@@ -2322,6 +2992,7 @@ static bool nvme_apst_get_transition_tim
 	}
 	return false;
 }
+#endif
 
 /*
  * APST (Autonomous Power State Transition) lets us program a table of power
@@ -2348,6 +3019,7 @@ static bool nvme_apst_get_transition_tim
  *
  * Users can set ps_max_latency_us to zero to turn off APST.
  */
+#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
 static int nvme_configure_apst(struct nvme_ctrl *ctrl)
 {
 	struct nvme_feat_auto_pst *table;
@@ -2474,6 +3146,7 @@ static void nvme_set_latency_tolerance(s
 			nvme_configure_apst(ctrl);
 	}
 }
+#endif
 
 struct nvme_core_quirk_entry {
 	/*
@@ -2941,7 +3614,9 @@ static int nvme_init_identify(struct nvm
 {
 	struct nvme_id_ctrl *id;
 	u32 max_hw_sectors;
+#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
 	bool prev_apst_enabled;
+#endif
 	int ret;
 
 	ret = nvme_identify_ctrl(ctrl, &id);
@@ -3025,6 +3700,7 @@ static int nvme_init_identify(struct nvm
 	} 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;
@@ -3039,6 +3715,7 @@ static int nvme_init_identify(struct nvm
 		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);
@@ -3076,10 +3753,12 @@ static int nvme_init_identify(struct nvm
 	if (ret < 0)
 		goto out_free;
 
+#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)
 		dev_pm_qos_hide_latency_tolerance(ctrl->device);
+#endif
 
 out_free:
 	kfree(id);
@@ -3114,17 +3793,21 @@ int nvme_init_ctrl_finish(struct nvme_ct
 	if (ret < 0)
 		return ret;
 
+#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
 	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
 
 	ret = nvme_configure_acre(ctrl);
 	if (ret < 0)
@@ -3226,8 +3909,10 @@ static ssize_t wwid_show(struct device *
 	int serial_len = sizeof(subsys->serial);
 	int model_len = sizeof(subsys->model);
 
+#ifdef HAVE_UUID_IS_NULL
 	if (!uuid_is_null(&ids->uuid))
 		return sysfs_emit(buf, "uuid.%pU\n", &ids->uuid);
+#endif
 
 	if (memchr_inv(ids->nguid, 0, sizeof(ids->nguid)))
 		return sysfs_emit(buf, "eui.%16phN\n", ids->nguid);
@@ -3248,12 +3933,14 @@ static ssize_t wwid_show(struct device *
 }
 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 sysfs_emit(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)
@@ -3263,11 +3950,13 @@ static ssize_t uuid_show(struct device *
 	/* 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)) {
 		dev_warn_ratelimited(dev,
 			"No UUID available providing old NGUID\n");
 		return sysfs_emit(buf, "%pU\n", ids->nguid);
 	}
+#endif
 	return sysfs_emit(buf, "%pU\n", &ids->uuid);
 }
 static DEVICE_ATTR_RO(uuid);
@@ -3289,7 +3978,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,
 #ifdef CONFIG_NVME_MULTIPATH
@@ -3306,11 +3997,13 @@ static umode_t nvme_ns_id_attrs_are_visi
 	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;
 	}
@@ -3329,7 +4022,11 @@ static umode_t nvme_ns_id_attrs_are_visi
 	return a->mode;
 }
 
+#ifdef HAVE_DEVICE_ADD_DISK_3_ARGS
 static const struct attribute_group nvme_ns_id_attr_group = {
+#else
+const struct attribute_group nvme_ns_id_attr_group = {
+#endif
 	.attrs		= nvme_ns_id_attrs,
 	.is_visible	= nvme_ns_id_attrs_are_visible,
 };
@@ -3368,6 +4065,7 @@ nvme_show_int_function(queue_count);
 nvme_show_int_function(sqsize);
 nvme_show_int_function(kato);
 
+#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)
@@ -3382,6 +4080,54 @@ static ssize_t nvme_sysfs_delete(struct
 		nvme_delete_ctrl_sync(ctrl);
 	return count;
 }
+#else
+static int __nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
+{
+	int ret = 0;
+
+	/*
+	 * Keep a reference until the work is flushed since ->delete_ctrl
+	 * can free the controller.
+	 */
+	nvme_get_ctrl(ctrl);
+	ret = nvme_delete_ctrl(ctrl);
+	if (!ret)
+		flush_work(&ctrl->delete_work);
+	nvme_put_ctrl(ctrl);
+	return ret;
+}
+
+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)
+{
+	struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+	int ret;
+
+	/* Can't delete non-created controllers */
+	if (!ctrl->created)
+		return -EBUSY;
+
+	/* 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,
@@ -3626,7 +4372,11 @@ static struct nvme_ns_head *nvme_find_ns
 static int nvme_subsys_check_duplicate_ids(struct nvme_subsystem *subsys,
 		struct nvme_ns_ids *ids)
 {
+#ifdef HAVE_UUID_IS_NULL
 	bool has_uuid = !uuid_is_null(&ids->uuid);
+#else
+	bool has_uuid = false;
+#endif
 	bool has_nguid = memchr_inv(ids->nguid, 0, sizeof(ids->nguid));
 	bool has_eui64 = memchr_inv(ids->eui64, 0, sizeof(ids->eui64));
 	struct nvme_ns_head *h;
@@ -3868,6 +4618,7 @@ static void nvme_alloc_ns(struct nvme_ct
 	if (!ns)
 		goto out_free_id;
 
+#ifdef HAVE_BLK_MQ_ALLOC_DISK
 	disk = blk_mq_alloc_disk(ctrl->tagset, ns);
 	if (IS_ERR(disk))
 		goto out_free_ns;
@@ -3876,19 +4627,61 @@ static void nvme_alloc_ns(struct nvme_ct
 
 	ns->disk = disk;
 	ns->queue = disk->queue;
+#else
+	ns->queue = blk_mq_init_queue(ctrl->tagset);
+	if (IS_ERR(ns->queue))
+		goto out_free_ns;
+#endif
 
+#ifdef HAVE_REQUEST_QUEUE_BACKING_DEV_INFO
 	if (ctrl->opts && ctrl->opts->data_digest)
+#ifdef HAVE_QUEUE_FLAG_STABLE_WRITES
 		blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, ns->queue);
+#else
+		ns->queue->backing_dev_info->capabilities
+			|= BDI_CAP_STABLE_WRITES;
+#endif
+#endif
 
 	blk_queue_flag_set(QUEUE_FLAG_NONROT, ns->queue);
+#ifdef HAVE_QUEUE_FLAG_PCI_P2PDMA
 	if (ctrl->ops->flags & NVME_F_PCI_P2PDMA)
 		blk_queue_flag_set(QUEUE_FLAG_PCI_P2PDMA, ns->queue);
+#endif
 
+#ifndef HAVE_BLK_MQ_ALLOC_DISK
+	ns->queue->queuedata = ns;
+#endif
 	ns->ctrl = ctrl;
 	kref_init(&ns->kref);
 
+#if defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE || defined HAVE_REVALIDATE_DISK_SIZE
+	 ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
+
+	 blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
+	 nvme_set_queue_limits(ctrl, ns->queue);
+#endif
+
 	if (nvme_init_ns_head(ns, nsid, ids, id->nmic & NVME_NS_NMIC_SHARED))
+#ifdef HAVE_BLK_MQ_ALLOC_DISK
 		goto out_cleanup_disk;
+#else
+		goto out_free_queue;
+
+	disk = alloc_disk_node(0, node);
+	if (!disk)
+		goto out_unlink_ns;
+
+	disk->fops = &nvme_bdev_ops;
+	disk->private_data = ns;
+	disk->queue = ns->queue;
+#if !defined(HAVE_DEVICE_ADD_DISK) && !defined(HAVE_DEVICE_ADD_DISK_3_ARGS)
+	disk->driverfs_dev = ctrl->device;
+#endif
+#ifdef HAVE_GENHD_FL_EXT_DEVT
+	disk->flags = GENHD_FL_EXT_DEVT;
+#endif
+#endif /* HAVE_BLK_MQ_ALLOC_DISK */
 
 	/*
 	 * Without the multipath code enabled, multiple controller per
@@ -3898,17 +4691,43 @@ static void nvme_alloc_ns(struct nvme_ct
 	if (!nvme_mpath_set_disk_name(ns, disk->disk_name, &disk->flags))
 		sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance,
 			ns->head->instance);
-
+#ifndef HAVE_BLK_MQ_ALLOC_DISK
+	ns->disk = disk;
+#endif
+#if defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE || defined HAVE_REVALIDATE_DISK_SIZE
+	if (__nvme_revalidate_disk(disk, id))
+#else
 	if (nvme_update_ns_info(ns, id))
+#endif
+#ifdef HAVE_BLK_MQ_ALLOC_DISK
 		goto out_unlink_ns;
+#else
+		goto out_put_disk;
+#endif
 
 	down_write(&ctrl->namespaces_rwsem);
 	nvme_ns_add_to_ctrl_list(ns);
 	up_write(&ctrl->namespaces_rwsem);
 	nvme_get_ctrl(ctrl);
 
+#ifdef HAVE_DEVICE_ADD_DISK_3_ARGS
+#ifdef HAVE_DEVICE_ADD_DISK_RETURN
 	if (device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups))
 		goto out_cleanup_ns_from_list;
+#else
+	device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups);
+#endif
+#else
+#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",
+			ns->disk->disk_name);
+#endif /* HAVE_DEVICE_ADD_DISK_3_ARGS */
 
 	if (!nvme_ns_head_multipath(ns->head))
 		nvme_add_ns_cdev(ns);
@@ -3918,12 +4737,19 @@ static void nvme_alloc_ns(struct nvme_ct
 	kfree(id);
 
 	return;
-
+#ifdef HAVE_DEVICE_ADD_DISK_RETURN
  out_cleanup_ns_from_list:
 	nvme_put_ctrl(ctrl);
 	down_write(&ctrl->namespaces_rwsem);
 	list_del_init(&ns->list);
 	up_write(&ctrl->namespaces_rwsem);
+#endif
+#ifndef HAVE_BLK_MQ_ALLOC_DISK
+ out_put_disk:
+	/* prevent double queue cleanup */
+	ns->disk->queue = NULL;
+	put_disk(ns->disk);
+#endif
  out_unlink_ns:
 	mutex_lock(&ctrl->subsys->lock);
 	list_del_rcu(&ns->siblings);
@@ -3931,8 +4757,17 @@ static void nvme_alloc_ns(struct nvme_ct
 		list_del_init(&ns->head->entry);
 	mutex_unlock(&ctrl->subsys->lock);
 	nvme_put_ns_head(ns->head);
+#ifdef HAVE_BLK_MQ_ALLOC_DISK
  out_cleanup_disk:
+#ifdef HAVE_BLK_CLEANUP_DISK
 	blk_cleanup_disk(disk);
+#else
+	put_disk(disk);
+#endif
+#else
+ out_free_queue:
+	blk_cleanup_queue(ns->queue);
+#endif
  out_free_ns:
 	kfree(ns);
  out_free_id:
@@ -3974,7 +4809,9 @@ static void nvme_ns_remove(struct nvme_n
 	if (!nvme_ns_head_multipath(ns->head))
 		nvme_cdev_del(&ns->cdev, &ns->cdev_device);
 	del_gendisk(ns->disk);
+#ifndef HAVE_BLK_MQ_DESTROY_QUEUE
 	blk_cleanup_queue(ns->queue);
+#endif
 
 	down_write(&ns->ctrl->namespaces_rwsem);
 	list_del_init(&ns->list);
@@ -4014,7 +4851,18 @@ static void nvme_validate_ns(struct nvme
 		goto out_free_id;
 	}
 
+#ifdef HAVE_REVALIDATE_DISK_SIZE
+	ret = nvme_revalidate_disk(ns->disk);
+	revalidate_disk_size(ns->disk, ret == 0);
+#elif defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE
+#ifdef HAVE_BDEV_NR_SECTORS
+	ret = nvme_revalidate_disk(ns->disk);
+#else
+	ret = revalidate_disk(ns->disk);
+#endif
+#else
 	ret = nvme_update_ns_info(ns, id);
+#endif
 
 out_free_id:
 	kfree(id);
@@ -4236,9 +5084,17 @@ void nvme_remove_namespaces(struct nvme_
 }
 EXPORT_SYMBOL_GPL(nvme_remove_namespaces);
 
+#ifdef HAVE_CLASS_DEV_UEVENT_CONST_DEV
+static int nvme_class_uevent(const struct device *dev, struct kobj_uevent_env *env)
+#else
 static int nvme_class_uevent(struct device *dev, struct kobj_uevent_env *env)
+#endif
 {
+#ifdef HAVE_CLASS_DEV_UEVENT_CONST_DEV
+	const struct nvme_ctrl *ctrl =
+#else
 	struct nvme_ctrl *ctrl =
+#endif
 		container_of(dev, struct nvme_ctrl, ctrl_device);
 	struct nvmf_ctrl_options *opts = ctrl->opts;
 	int ret;
@@ -4449,7 +5305,9 @@ void nvme_uninit_ctrl(struct nvme_ctrl *
 {
 	nvme_hwmon_exit(ctrl);
 	nvme_fault_inject_fini(&ctrl->fault_inject);
+#ifdef HAVE_DEV_PM_INFO_SET_LATENCY_TOLERANCE
 	dev_pm_qos_hide_latency_tolerance(ctrl->device);
+#endif
 	cdev_device_del(&ctrl->cdev, ctrl->device);
 	nvme_put_ctrl(ctrl);
 }
@@ -4563,9 +5421,11 @@ int nvme_init_ctrl(struct nvme_ctrl *ctr
 	 * 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
 
 	nvme_fault_inject_init(&ctrl->fault_inject, dev_name(ctrl->device));
 	nvme_mpath_init_ctrl(ctrl);
@@ -4586,17 +5446,80 @@ EXPORT_SYMBOL_GPL(nvme_init_ctrl);
 static void nvme_start_ns_queue(struct nvme_ns *ns)
 {
 	if (test_and_clear_bit(NVME_NS_STOPPED, &ns->flags))
+#ifdef HAVE_BLKDEV_QUEUE_FLAG_QUIESCED
+		blk_mq_unquiesce_queue(ns->queue);
+#else
+#ifdef HAVE_BLK_MQ_QUIESCE_QUEUE
+		queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, ns->queue);
+#endif
+#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
 		blk_mq_unquiesce_queue(ns->queue);
+#else
+		blk_mq_start_stopped_hw_queues(ns->queue, true);
+#endif
+#endif /* HAVE_BLKDEV_QUEUE_FLAG_QUIESCED */
 }
 
 static void nvme_stop_ns_queue(struct nvme_ns *ns)
 {
-	if (!test_and_set_bit(NVME_NS_STOPPED, &ns->flags))
+	if (!test_and_set_bit(NVME_NS_STOPPED, &ns->flags)) {
+#ifdef HAVE_BLK_MQ_QUIESCE_QUEUE
+#ifdef HAVE_BLKDEV_QUEUE_FLAG_QUIESCED
 		blk_mq_quiesce_queue(ns->queue);
-	else
+#else
+		spin_lock_irq(ns->queue->queue_lock);
+		queue_flag_set(QUEUE_FLAG_STOPPED, ns->queue);
+		spin_unlock_irq(ns->queue->queue_lock);
+		blk_mq_quiesce_queue(ns->queue);
+#endif
+#else
+		blk_mq_cancel_requeue_work(ns->queue);
+		blk_mq_stop_hw_queues(ns->queue);
+#endif
+#ifdef HAVE_BLK_MQ_WAIT_QUIESCE_DONE
+	} else {
+#ifdef HAVE_BLK_MQ_WAIT_QUIESCE_DONE_TAGSET
+		blk_mq_wait_quiesce_done(ns->queue->tag_set);
+#else
 		blk_mq_wait_quiesce_done(ns->queue);
+#endif
+	}
+#else
+	}
+#endif
 }
 
+#if defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE
+static void nvme_update_bdev_size(struct gendisk *disk)
+{
+	struct block_device *bdev = bdget_disk(disk, 0);
+
+	if (bdev) {
+#ifdef HAVE_BD_SET_NR_SECTORS
+		bd_set_nr_sectors(bdev, get_capacity(disk));
+#else
+		if (bdev->bd_disk) {
+			bd_set_size(bdev, get_capacity(disk) << SECTOR_SHIFT);
+		} else {
+#ifdef HAVE_INODE_LOCK
+			inode_lock(bdev->bd_inode);
+#else
+			mutex_lock(&bdev->bd_inode->i_mutex);
+#endif
+			i_size_write(bdev->bd_inode,
+				     get_capacity(disk) << SECTOR_SHIFT);
+#ifdef HAVE_INODE_LOCK
+			inode_unlock(bdev->bd_inode);
+#else
+			mutex_unlock(&bdev->bd_inode->i_mutex);
+#endif
+		}
+#endif
+		bdput(bdev);
+	}
+}
+#endif
+
 /*
  * Prepare a queue for teardown.
  *
@@ -4610,10 +5533,19 @@ static void nvme_set_queue_dying(struct
 	if (test_and_set_bit(NVME_NS_DEAD, &ns->flags))
 		return;
 
+#ifdef HAVE_BLK_MARK_DISK_DEAD
 	blk_mark_disk_dead(ns->disk);
+#else
+	blk_set_queue_dying(ns->queue);
+#endif
 	nvme_start_ns_queue(ns);
 
+#if defined HAVE_BD_SET_NR_SECTORS || defined HAVE_BD_SET_SIZE
+	set_capacity(ns->disk, 0);
+	nvme_update_bdev_size(ns->disk);
+#else
 	set_capacity_and_notify(ns->disk, 0);
+#endif
 }
 
 /**
@@ -4683,7 +5615,11 @@ void nvme_start_freeze(struct nvme_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);
@@ -4713,16 +5649,30 @@ EXPORT_SYMBOL_GPL(nvme_start_queues);
 void nvme_stop_admin_queue(struct nvme_ctrl *ctrl)
 {
 	if (!test_and_set_bit(NVME_CTRL_ADMIN_Q_STOPPED, &ctrl->flags))
+#ifdef HAVE_BLK_MQ_UNQUIESCE_QUEUE
 		blk_mq_quiesce_queue(ctrl->admin_q);
+#else
+		blk_mq_stop_hw_queues(ctrl->admin_q);
+#endif
+#ifdef HAVE_BLK_MQ_WAIT_QUIESCE_DONE
 	else
+#ifdef HAVE_BLK_MQ_WAIT_QUIESCE_DONE_TAGSET
+		blk_mq_wait_quiesce_done(ctrl->admin_q->tag_set);
+#else
 		blk_mq_wait_quiesce_done(ctrl->admin_q);
+#endif
+#endif
 }
 EXPORT_SYMBOL_GPL(nvme_stop_admin_queue);
 
 void nvme_start_admin_queue(struct nvme_ctrl *ctrl)
 {
 	if (test_and_clear_bit(NVME_CTRL_ADMIN_Q_STOPPED, &ctrl->flags))
+#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
 }
 EXPORT_SYMBOL_GPL(nvme_start_admin_queue);
 
@@ -4833,14 +5783,22 @@ static int __init nvme_core_init(void)
 	if (result < 0)
 		goto destroy_delete_wq;
 
+#ifdef HAVE_CLASS_CREATE_GET_1_PARAM
+	nvme_class = class_create("nvme");
+#else
 	nvme_class = class_create(THIS_MODULE, "nvme");
+#endif
 	if (IS_ERR(nvme_class)) {
 		result = PTR_ERR(nvme_class);
 		goto unregister_chrdev;
 	}
 	nvme_class->dev_uevent = nvme_class_uevent;
 
+#ifdef HAVE_CLASS_CREATE_GET_1_PARAM
+	nvme_subsys_class = class_create("nvme-subsystem");
+#else
 	nvme_subsys_class = class_create(THIS_MODULE, "nvme-subsystem");
+#endif
 	if (IS_ERR(nvme_subsys_class)) {
 		result = PTR_ERR(nvme_subsys_class);
 		goto destroy_class;
@@ -4851,7 +5809,11 @@ static int __init nvme_core_init(void)
 	if (result < 0)
 		goto destroy_subsys_class;
 
+#ifdef HAVE_CLASS_CREATE_GET_1_PARAM
+	nvme_ns_chr_class = class_create("nvme-generic");
+#else
 	nvme_ns_chr_class = class_create(THIS_MODULE, "nvme-generic");
+#endif
 	if (IS_ERR(nvme_ns_chr_class)) {
 		result = PTR_ERR(nvme_ns_chr_class);
 		goto unregister_generic_ns;
@@ -4892,6 +5854,9 @@ static void __exit nvme_core_exit(void)
 }
 
 MODULE_LICENSE("GPL");
+#ifdef RETPOLINE_MLNX
+MODULE_INFO(retpoline, "Y");
+#endif
 MODULE_VERSION("1.0");
 module_init(nvme_core_init);
 module_exit(nvme_core_exit);
