req->cmd_type = REQ_TYPE_DRV_PRIV;
        req->cmd_flags |= REQ_FAILFAST_DRIVER;
-       req->cmd = (unsigned char *)cmd;
-       req->cmd_len = sizeof(struct nvme_command);
+       nvme_req(req)->cmd = cmd;
 
        return req;
 }
        int ret = 0;
 
        if (req->cmd_type == REQ_TYPE_DRV_PRIV)
-               memcpy(cmd, req->cmd, sizeof(*cmd));
+               memcpy(cmd, nvme_req(req)->cmd, sizeof(*cmd));
        else if (req_op(req) == REQ_OP_FLUSH)
                nvme_setup_flush(ns, cmd);
        else if (req_op(req) == REQ_OP_DISCARD)
  * if the result is positive, it's an NVM Express status code
  */
 int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
-               struct nvme_completion *cqe, void *buffer, unsigned bufflen,
+               union nvme_result *result, void *buffer, unsigned bufflen,
                unsigned timeout, int qid, int at_head, int flags)
 {
        struct request *req;
                return PTR_ERR(req);
 
        req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
-       req->special = cqe;
 
        if (buffer && bufflen) {
                ret = blk_rq_map_kern(q, req, buffer, bufflen, GFP_KERNEL);
        }
 
        blk_execute_rq(req->q, NULL, req, at_head);
+       if (result)
+               *result = nvme_req(req)->result;
        ret = req->errors;
  out:
        blk_mq_free_request(req);
                u32 *result, unsigned timeout)
 {
        bool write = nvme_is_write(cmd);
-       struct nvme_completion cqe;
        struct nvme_ns *ns = q->queuedata;
        struct gendisk *disk = ns ? ns->disk : NULL;
        struct request *req;
                return PTR_ERR(req);
 
        req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
-       req->special = &cqe;
 
        if (ubuffer && bufflen) {
                ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
        blk_execute_rq(req->q, disk, req, 0);
        ret = req->errors;
        if (result)
-               *result = le32_to_cpu(cqe.result);
+               *result = le32_to_cpu(nvme_req(req)->result.u32);
        if (meta && !ret && !write) {
                if (copy_to_user(meta_buffer, meta, meta_len))
                        ret = -EFAULT;
                      void *buffer, size_t buflen, u32 *result)
 {
        struct nvme_command c;
-       struct nvme_completion cqe;
+       union nvme_result res;
        int ret;
 
        memset(&c, 0, sizeof(c));
        c.features.nsid = cpu_to_le32(nsid);
        c.features.fid = cpu_to_le32(fid);
 
-       ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, buffer, buflen, 0,
+       ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res, buffer, buflen, 0,
                        NVME_QID_ANY, 0, 0);
        if (ret >= 0 && result)
-               *result = le32_to_cpu(cqe.result);
+               *result = le32_to_cpu(res.u32);
        return ret;
 }
 
                      void *buffer, size_t buflen, u32 *result)
 {
        struct nvme_command c;
-       struct nvme_completion cqe;
+       union nvme_result res;
        int ret;
 
        memset(&c, 0, sizeof(c));
        c.features.fid = cpu_to_le32(fid);
        c.features.dword11 = cpu_to_le32(dword11);
 
-       ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe,
+       ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res,
                        buffer, buflen, 0, NVME_QID_ANY, 0, 0);
        if (ret >= 0 && result)
-               *result = le32_to_cpu(cqe.result);
+               *result = le32_to_cpu(res.u32);
        return ret;
 }
 
                struct nvme_completion *cqe)
 {
        u16 status = le16_to_cpu(cqe->status) >> 1;
-       u32 result = le32_to_cpu(cqe->result);
+       u32 result = le32_to_cpu(cqe->result.u32);
 
        if (status == NVME_SC_SUCCESS || status == NVME_SC_ABORT_REQ) {
                ++ctrl->event_limit;
 
 int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val)
 {
        struct nvme_command cmd;
-       struct nvme_completion cqe;
+       union nvme_result res;
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.prop_get.fctype = nvme_fabrics_type_property_get;
        cmd.prop_get.offset = cpu_to_le32(off);
 
-       ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &cqe, NULL, 0, 0,
+       ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res, NULL, 0, 0,
                        NVME_QID_ANY, 0, 0);
 
        if (ret >= 0)
-               *val = le64_to_cpu(cqe.result64);
+               *val = le64_to_cpu(res.u64);
        if (unlikely(ret != 0))
                dev_err(ctrl->device,
                        "Property Get error: %d, offset %#x\n",
 int nvmf_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val)
 {
        struct nvme_command cmd;
-       struct nvme_completion cqe;
+       union nvme_result res;
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.prop_get.attrib = 1;
        cmd.prop_get.offset = cpu_to_le32(off);
 
-       ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &cqe, NULL, 0, 0,
+       ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &res, NULL, 0, 0,
                        NVME_QID_ANY, 0, 0);
 
        if (ret >= 0)
-               *val = le64_to_cpu(cqe.result64);
+               *val = le64_to_cpu(res.u64);
        if (unlikely(ret != 0))
                dev_err(ctrl->device,
                        "Property Get error: %d, offset %#x\n",
 int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
 {
        struct nvme_command cmd;
-       struct nvme_completion cqe;
+       union nvme_result res;
        struct nvmf_connect_data *data;
        int ret;
 
        strncpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE);
        strncpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE);
 
-       ret = __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, &cqe,
+       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);
        if (ret) {
-               nvmf_log_connect_error(ctrl, ret, le32_to_cpu(cqe.result),
+               nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
                                       &cmd, data);
                goto out_free_data;
        }
 
-       ctrl->cntlid = le16_to_cpu(cqe.result16);
+       ctrl->cntlid = le16_to_cpu(res.u16);
 
 out_free_data:
        kfree(data);
 {
        struct nvme_command cmd;
        struct nvmf_connect_data *data;
-       struct nvme_completion cqe;
+       union nvme_result res;
        int ret;
 
        memset(&cmd, 0, sizeof(cmd));
        strncpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE);
        strncpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE);
 
-       ret = __nvme_submit_sync_cmd(ctrl->connect_q, &cmd, &cqe,
+       ret = __nvme_submit_sync_cmd(ctrl->connect_q, &cmd, &res,
                        data, sizeof(*data), 0, qid, 1,
                        BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
        if (ret) {
-               nvmf_log_connect_error(ctrl, ret, le32_to_cpu(cqe.result),
+               nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
                                       &cmd, data);
        }
        kfree(data);
 
        };
 };
 
-struct nvme_nvm_completion {
-       __le64  result;         /* Used by LightNVM to return ppa completions */
-       __le16  sq_head;        /* how much of this queue may be reclaimed */
-       __le16  sq_id;          /* submission queue that generated this entry */
-       __u16   command_id;     /* of the command which completed */
-       __le16  status;         /* did the command fail, and if so, why? */
-};
-
 #define NVME_NVM_LP_MLC_PAIRS 886
 struct nvme_nvm_lp_mlc {
        __le16                  num_pairs;
 static void nvme_nvm_end_io(struct request *rq, int error)
 {
        struct nvm_rq *rqd = rq->end_io_data;
-       struct nvme_nvm_completion *cqe = rq->special;
-
-       if (cqe)
-               rqd->ppa_status = le64_to_cpu(cqe->result);
 
+       rqd->ppa_status = nvme_req(rq)->result.u64;
        nvm_end_io(rqd, error);
 
        kfree(rq->cmd);
        struct bio *bio = rqd->bio;
        struct nvme_nvm_command *cmd;
 
-       rq = blk_mq_alloc_request(q, bio_data_dir(bio), 0);
-       if (IS_ERR(rq))
+       cmd = kzalloc(sizeof(struct nvme_nvm_command), GFP_KERNEL);
+       if (!cmd)
                return -ENOMEM;
 
-       cmd = kzalloc(sizeof(struct nvme_nvm_command) +
-                               sizeof(struct nvme_nvm_completion), GFP_KERNEL);
-       if (!cmd) {
-               blk_mq_free_request(rq);
+       rq = nvme_alloc_request(q, (struct nvme_command *)cmd, 0, NVME_QID_ANY);
+       if (IS_ERR(rq)) {
+               kfree(cmd);
                return -ENOMEM;
        }
+       rq->cmd_flags &= ~REQ_FAILFAST_DRIVER;
 
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
        rq->ioprio = bio_prio(bio);
-
        if (bio_has_data(bio))
                rq->nr_phys_segments = bio_phys_segments(q, bio);
 
 
        nvme_nvm_rqtocmd(rq, rqd, ns, cmd);
 
-       rq->cmd = (unsigned char *)cmd;
-       rq->cmd_len = sizeof(struct nvme_nvm_command);
-       rq->special = cmd + 1;
-
        rq->end_io_data = rqd;
 
        blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_io);
 
        NVME_QUIRK_DELAY_BEFORE_CHK_RDY         = (1 << 3),
 };
 
+/*
+ * Common request structure for NVMe passthrough.  All drivers must have
+ * this structure as the first member of their request-private data.
+ */
+struct nvme_request {
+       struct nvme_command     *cmd;
+       union nvme_result       result;
+};
+
+static inline struct nvme_request *nvme_req(struct request *req)
+{
+       return blk_mq_rq_to_pdu(req);
+}
+
 /* The below value is the specific amount of delay needed before checking
  * readiness in case of the PCI_DEVICE(0x1c58, 0x0003), which needs the
  * NVME_QUIRK_DELAY_BEFORE_CHK_RDY quirk enabled. The value (in ms) was
 int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                void *buf, unsigned bufflen);
 int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
-               struct nvme_completion *cqe, void *buffer, unsigned bufflen,
+               union nvme_result *result, void *buffer, unsigned bufflen,
                unsigned timeout, int qid, int at_head, int flags);
 int nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
                void __user *ubuffer, unsigned bufflen, u32 *result,
 
  * allocated to store the PRP list.
  */
 struct nvme_iod {
+       struct nvme_request req;
        struct nvme_queue *nvmeq;
        int aborted;
        int npages;             /* In the PRP list. 0 means small pool in use */
                }
 
                req = blk_mq_tag_to_rq(*nvmeq->tags, cqe.command_id);
-               if (req->cmd_type == REQ_TYPE_DRV_PRIV && req->special)
-                       memcpy(req->special, &cqe, sizeof(cqe));
+               nvme_req(req)->result = cqe.result;
                blk_mq_complete_request(req, le16_to_cpu(cqe.status) >> 1);
 
        }
 
 
 struct nvme_rdma_queue;
 struct nvme_rdma_request {
+       struct nvme_request     req;
        struct ib_mr            *mr;
        struct nvme_rdma_qe     sqe;
        struct ib_sge           sge[1 + NVME_RDMA_MAX_INLINE_SEGMENTS];
 static int nvme_rdma_process_nvme_rsp(struct nvme_rdma_queue *queue,
                struct nvme_completion *cqe, struct ib_wc *wc, int tag)
 {
-       u16 status = le16_to_cpu(cqe->status);
        struct request *rq;
        struct nvme_rdma_request *req;
        int ret = 0;
 
-       status >>= 1;
-
        rq = blk_mq_tag_to_rq(nvme_rdma_tagset(queue), cqe->command_id);
        if (!rq) {
                dev_err(queue->ctrl->ctrl.device,
        }
        req = blk_mq_rq_to_pdu(rq);
 
-       if (rq->cmd_type == REQ_TYPE_DRV_PRIV && rq->special)
-               memcpy(rq->special, cqe, sizeof(*cqe));
-
        if (rq->tag == tag)
                ret = 1;
 
            wc->ex.invalidate_rkey == req->mr->rkey)
                req->mr->need_inval = false;
 
-       blk_mq_complete_request(rq, status);
-
+       req->req.result = cqe->result;
+       blk_mq_complete_request(rq, le16_to_cpu(cqe->status) >> 1);
        return ret;
 }
 
 
        if (!subsys) {
                pr_warn("connect request for invalid subsystem %s!\n",
                        subsysnqn);
-               req->rsp->result = IPO_IATTR_CONNECT_DATA(subsysnqn);
+               req->rsp->result.u32 = IPO_IATTR_CONNECT_DATA(subsysnqn);
                return NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
        }
 
 
        pr_warn("could not find controller %d for subsys %s / host %s\n",
                cntlid, subsysnqn, hostnqn);
-       req->rsp->result = IPO_IATTR_CONNECT_DATA(cntlid);
+       req->rsp->result.u32 = IPO_IATTR_CONNECT_DATA(cntlid);
        status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
 
 out:
        if (!subsys) {
                pr_warn("connect request for invalid subsystem %s!\n",
                        subsysnqn);
-               req->rsp->result = IPO_IATTR_CONNECT_DATA(subsysnqn);
+               req->rsp->result.u32 = IPO_IATTR_CONNECT_DATA(subsysnqn);
                goto out;
        }
 
        if (!nvmet_host_allowed(req, subsys, hostnqn)) {
                pr_info("connect by host %s for subsystem %s not allowed\n",
                        hostnqn, subsysnqn);
-               req->rsp->result = IPO_IATTR_CONNECT_DATA(hostnqn);
+               req->rsp->result.u32 = IPO_IATTR_CONNECT_DATA(hostnqn);
                up_read(&nvmet_config_sem);
                goto out_put_subsystem;
        }
 
                }
        }
 
-       req->rsp->result64 = cpu_to_le64(val);
+       req->rsp->result.u64 = cpu_to_le64(val);
        nvmet_req_complete(req, status);
 }
 
        d = kmap(sg_page(req->sg)) + req->sg->offset;
 
        /* zero out initial completion result, assign values as needed */
-       req->rsp->result = 0;
+       req->rsp->result.u32 = 0;
 
        if (c->recfmt != 0) {
                pr_warn("invalid connect version (%d).\n",
                pr_warn("connect attempt for invalid controller ID %#x\n",
                        d->cntlid);
                status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
-               req->rsp->result = IPO_IATTR_CONNECT_DATA(cntlid);
+               req->rsp->result.u32 = IPO_IATTR_CONNECT_DATA(cntlid);
                goto out;
        }
 
 
        pr_info("creating controller %d for NQN %s.\n",
                        ctrl->cntlid, ctrl->hostnqn);
-       req->rsp->result16 = cpu_to_le16(ctrl->cntlid);
+       req->rsp->result.u16 = cpu_to_le16(ctrl->cntlid);
 
 out:
        kunmap(sg_page(req->sg));
        d = kmap(sg_page(req->sg)) + req->sg->offset;
 
        /* zero out initial completion result, assign values as needed */
-       req->rsp->result = 0;
+       req->rsp->result.u32 = 0;
 
        if (c->recfmt != 0) {
                pr_warn("invalid connect version (%d).\n",
        if (unlikely(qid > ctrl->subsys->max_qid)) {
                pr_warn("invalid queue id (%d)\n", qid);
                status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
-               req->rsp->result = IPO_IATTR_CONNECT_SQE(qid);
+               req->rsp->result.u32 = IPO_IATTR_CONNECT_SQE(qid);
                goto out_ctrl_put;
        }
 
        status = nvmet_install_queue(ctrl, req);
        if (status) {
                /* pass back cntlid that had the issue of installing queue */
-               req->rsp->result16 = cpu_to_le16(ctrl->cntlid);
+               req->rsp->result.u16 = cpu_to_le16(ctrl->cntlid);
                goto out_ctrl_put;
        }
 
 
        (NVME_LOOP_AQ_DEPTH - NVME_LOOP_NR_AEN_COMMANDS)
 
 struct nvme_loop_iod {
+       struct nvme_request     nvme_req;
        struct nvme_command     cmd;
        struct nvme_completion  rsp;
        struct nvmet_req        req;
        blk_mq_end_request(req, error);
 }
 
-static void nvme_loop_queue_response(struct nvmet_req *nvme_req)
+static void nvme_loop_queue_response(struct nvmet_req *req)
 {
        struct nvme_loop_iod *iod =
-               container_of(nvme_req, struct nvme_loop_iod, req);
+               container_of(req, struct nvme_loop_iod, req);
        struct nvme_completion *cqe = &iod->rsp;
 
        /*
                        cqe->command_id >= NVME_LOOP_AQ_BLKMQ_DEPTH)) {
                nvme_complete_async_event(&iod->queue->ctrl->ctrl, cqe);
        } else {
-               struct request *req = blk_mq_rq_from_pdu(iod);
+               struct request *rq = blk_mq_rq_from_pdu(iod);
 
-               if (req->cmd_type == REQ_TYPE_DRV_PRIV && req->special)
-                       memcpy(req->special, cqe, sizeof(*cqe));
-               blk_mq_complete_request(req, le16_to_cpu(cqe->status) >> 1);
+               iod->nvme_req.result = cqe->result;
+               blk_mq_complete_request(rq, le16_to_cpu(cqe->status) >> 1);
        }
 }
 
 
 
 static inline void nvmet_set_result(struct nvmet_req *req, u32 result)
 {
-       req->rsp->result = cpu_to_le32(result);
+       req->rsp->result.u32 = cpu_to_le32(result);
 }
 
 /*
 
        /*
         * Used by Admin and Fabrics commands to return data:
         */
-       union {
-               __le16  result16;
-               __le32  result;
-               __le64  result64;
-       };
+       union nvme_result {
+               __le16  u16;
+               __le32  u32;
+               __le64  u64;
+       } result;
        __le16  sq_head;        /* how much of this queue may be reclaimed */
        __le16  sq_id;          /* submission queue that generated this entry */
        __u16   command_id;     /* of the command which completed */