Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/nvme/host/constants.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ static const char * const nvme_ops[] = {
[nvme_cmd_resv_report] = "Reservation Report",
[nvme_cmd_resv_acquire] = "Reservation Acquire",
[nvme_cmd_resv_release] = "Reservation Release",
[nvme_cmd_cancel] = "Cancel",
[nvme_cmd_zone_mgmt_send] = "Zone Management Send",
[nvme_cmd_zone_mgmt_recv] = "Zone Management Receive",
[nvme_cmd_zone_append] = "Zone Append",
Expand Down
83 changes: 82 additions & 1 deletion drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,20 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode)
}
EXPORT_SYMBOL_NS_GPL(nvme_command_effects, "NVME_TARGET_PASSTHRU");

bool nvme_io_command_supported(struct nvme_ctrl *ctrl, u8 opcode)
{
u32 effects = le32_to_cpu(ctrl->effects->iocs[opcode]);

return effects & NVME_CMD_EFFECTS_CSUPP;
}
EXPORT_SYMBOL_GPL(nvme_io_command_supported);

bool nvme_is_cancel(struct nvme_command *cmd)
{
return cmd->common.opcode == nvme_cmd_cancel;
}
EXPORT_SYMBOL_GPL(nvme_is_cancel);

u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode)
{
u32 effects = nvme_command_effects(ctrl, ns, opcode);
Expand Down Expand Up @@ -3105,6 +3119,67 @@ int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi,
return nvme_submit_sync_cmd(ctrl->admin_q, &c, log, size);
}

static enum rq_end_io_ret nvme_cancel_endio(struct request *req, blk_status_t error)
{
struct nvme_ctrl *ctrl = req->end_io_data;
u32 result;
u16 imm_abrts, def_abrts;

if (!error) {
result = le32_to_cpu(nvme_req(req)->result.u32);
def_abrts = upper_16_bits(result);
imm_abrts = lower_16_bits(result);

dev_warn(ctrl->device,
"Cancel status: 0x0 imm abrts = %u def abrts = %u",
imm_abrts, def_abrts);
} else {
dev_warn(ctrl->device, "Cancel status: 0x%x",
nvme_req(req)->status);
}

blk_mq_free_request(req);
return RQ_END_IO_NONE;
}

int nvme_submit_cancel_req(struct nvme_ctrl *ctrl, struct request *rq,
unsigned int sqid, int action)
{
struct nvme_command c = { };
struct request *cancel_req;

if (sqid == 0)
return -EINVAL;

c.cancel.opcode = nvme_cmd_cancel;
c.cancel.sqid = cpu_to_le32(sqid);
c.cancel.nsid = NVME_NSID_ALL;
c.cancel.action = action;
if (action == NVME_CANCEL_ACTION_SINGLE_CMD)
c.cancel.cid = nvme_cid(rq);
else
c.cancel.cid = 0xFFFF;

cancel_req = blk_mq_alloc_request_hctx(rq->q, nvme_req_op(&c),
BLK_MQ_REQ_NOWAIT |
BLK_MQ_REQ_RESERVED,
sqid - 1);
if (IS_ERR(cancel_req)) {
dev_warn(ctrl->device, "%s: Could not allocate the Cancel "
"command", __func__);
return PTR_ERR(cancel_req);
}

nvme_init_request(cancel_req, &c);
cancel_req->end_io = nvme_cancel_endio;
cancel_req->end_io_data = ctrl;

blk_execute_rq_nowait(cancel_req, false);

return 0;
}
EXPORT_SYMBOL_GPL(nvme_submit_cancel_req);

static int nvme_get_effects_log(struct nvme_ctrl *ctrl, u8 csi,
struct nvme_effects_log **log)
{
Expand Down Expand Up @@ -4675,9 +4750,14 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
*/
if (ctrl->quirks & NVME_QUIRK_SHARED_TAGS)
set->reserved_tags = NVME_AQ_DEPTH;
else if (ctrl->ops->flags & NVME_F_FABRICS)
else if (ctrl->ops->flags & NVME_F_FABRICS) {
/* Reserved for fabric connect */
set->reserved_tags = 1;
if (nvme_io_command_supported(ctrl, nvme_cmd_cancel)) {
/* Reserved for cancel commands */
set->reserved_tags += NVME_RSV_CANCEL_MAX;
}
}
set->numa_node = ctrl->numa_node;
if (ctrl->ops->flags & NVME_F_BLOCKING)
set->flags |= BLK_MQ_F_BLOCKING;
Expand Down Expand Up @@ -5087,6 +5167,7 @@ static inline void _nvme_check_size(void)
BUILD_BUG_ON(sizeof(struct nvme_dsm_cmd) != 64);
BUILD_BUG_ON(sizeof(struct nvme_write_zeroes_cmd) != 64);
BUILD_BUG_ON(sizeof(struct nvme_abort_cmd) != 64);
BUILD_BUG_ON(sizeof(struct nvme_cancel_cmd) != 64);
BUILD_BUG_ON(sizeof(struct nvme_get_log_page_command) != 64);
BUILD_BUG_ON(sizeof(struct nvme_command) != 64);
BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != NVME_IDENTIFY_DATA_SIZE);
Expand Down
4 changes: 4 additions & 0 deletions drivers/nvme/host/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,8 @@ int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
void nvme_queue_scan(struct nvme_ctrl *ctrl);
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi,
void *log, size_t size, u64 offset);
int nvme_submit_cancel_req(struct nvme_ctrl *ctrl, struct request *rq,
unsigned int sqid, int action);
bool nvme_tryget_ns_head(struct nvme_ns_head *head);
void nvme_put_ns_head(struct nvme_ns_head *head);
int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
Expand Down Expand Up @@ -1187,6 +1189,8 @@ static inline void nvme_auth_revoke_tls_key(struct nvme_ctrl *ctrl) {};

u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
u8 opcode);
bool nvme_io_command_supported(struct nvme_ctrl *ctrl, u8 opcode);
bool nvme_is_cancel(struct nvme_command *cmd);
u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode);
int nvme_execute_rq(struct request *rq, bool at_head);
void nvme_passthru_end(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 effects,
Expand Down
50 changes: 46 additions & 4 deletions drivers/nvme/host/rdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,15 @@ struct nvme_rdma_request {
struct nvme_rdma_sgl data_sgl;
struct nvme_rdma_sgl *metadata_sgl;
bool use_sig_mr;
bool aborted;
};

enum nvme_rdma_queue_flags {
NVME_RDMA_Q_ALLOCATED = 0,
NVME_RDMA_Q_LIVE = 1,
NVME_RDMA_Q_TR_READY = 2,
NVME_RDMA_Q_CANCEL_ONE = 3,
NVME_RDMA_Q_CANCEL_ALL = 4,
};

struct nvme_rdma_queue {
Expand Down Expand Up @@ -619,6 +622,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
}

set_bit(NVME_RDMA_Q_ALLOCATED, &queue->flags);
clear_bit(NVME_RDMA_Q_CANCEL_ONE, &queue->flags);
clear_bit(NVME_RDMA_Q_CANCEL_ALL, &queue->flags);

return 0;

Expand Down Expand Up @@ -1954,16 +1959,18 @@ static enum blk_eh_timer_return nvme_rdma_timeout(struct request *rq)
{
struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
struct nvme_rdma_queue *queue = req->queue;
struct nvme_rdma_ctrl *ctrl = queue->ctrl;
struct nvme_rdma_ctrl *rdma_ctrl = queue->ctrl;
struct nvme_ctrl *ctrl = &rdma_ctrl->ctrl;
struct nvme_command *cmd = req->req.cmd;
int qid = nvme_rdma_queue_idx(queue);
int error, action;

dev_warn(ctrl->ctrl.device,
dev_warn(ctrl->device,
"I/O tag %d (%04x) opcode %#x (%s) QID %d timeout\n",
rq->tag, nvme_cid(rq), cmd->common.opcode,
nvme_fabrics_opcode_str(qid, cmd), qid);

if (nvme_ctrl_state(&ctrl->ctrl) != NVME_CTRL_LIVE) {
if (nvme_ctrl_state(ctrl) != NVME_CTRL_LIVE) {
/*
* If we are resetting, connecting or deleting we should
* complete immediately because we may block controller
Expand All @@ -1981,11 +1988,40 @@ static enum blk_eh_timer_return nvme_rdma_timeout(struct request *rq)
return BLK_EH_DONE;
}

if (!req->aborted) {
if (!nvme_io_command_supported(ctrl, nvme_cmd_cancel) || !qid)
goto err_recovery;

if (!test_and_set_bit(NVME_RDMA_Q_CANCEL_ONE, &queue->flags)) {
action = NVME_CANCEL_ACTION_SINGLE_CMD;
} else if (!test_and_set_bit(NVME_RDMA_Q_CANCEL_ALL,
&queue->flags)) {
action = NVME_CANCEL_ACTION_MUL_CMD;
} else {
/* No free reserved commands.
* this means a "multiple commands" cancel
* is currently under execution and this request
* is likely to be canceled. Mark this
* request as aborted and reset the timer.
*/
goto abort;
}

error = nvme_submit_cancel_req(ctrl, rq, qid, action);
if (error)
goto err_recovery;

abort:
req->aborted = true;
return BLK_EH_RESET_TIMER;
}

/*
* LIVE state should trigger the normal error recovery which will
* handle completing this request.
*/
nvme_rdma_error_recovery(ctrl);
err_recovery:
nvme_rdma_error_recovery(rdma_ctrl);
return BLK_EH_RESET_TIMER;
}

Expand All @@ -2009,6 +2045,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
return nvme_fail_nonready_command(&queue->ctrl->ctrl, rq);

dev = queue->device->dev;
req->aborted = false;

req->sqe.dma = ib_dma_map_single(dev, req->sqe.data,
sizeof(struct nvme_command),
Expand Down Expand Up @@ -2113,6 +2150,7 @@ static void nvme_rdma_complete_rq(struct request *rq)
struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
struct nvme_rdma_queue *queue = req->queue;
struct ib_device *ibdev = queue->device->dev;
bool is_cancel = nvme_is_cancel(req->req.cmd);

if (req->use_sig_mr)
nvme_rdma_check_pi_status(req);
Expand All @@ -2121,6 +2159,10 @@ static void nvme_rdma_complete_rq(struct request *rq)
ib_dma_unmap_single(ibdev, req->sqe.dma, sizeof(struct nvme_command),
DMA_TO_DEVICE);
nvme_complete_rq(rq);
if (is_cancel) {
if (!test_and_clear_bit(NVME_RDMA_Q_CANCEL_ALL, &queue->flags))
clear_bit(NVME_RDMA_Q_CANCEL_ONE, &queue->flags);
}
}

static void nvme_rdma_map_queues(struct blk_mq_tag_set *set)
Expand Down
62 changes: 57 additions & 5 deletions drivers/nvme/host/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,16 @@ struct nvme_tcp_request {
size_t offset;
size_t data_sent;
enum nvme_tcp_send_state state;
bool aborted;
};

enum nvme_tcp_queue_flags {
NVME_TCP_Q_ALLOCATED = 0,
NVME_TCP_Q_LIVE = 1,
NVME_TCP_Q_POLLING = 2,
NVME_TCP_Q_IO_CPU_SET = 3,
NVME_TCP_Q_CANCEL_ONE = 4,
NVME_TCP_Q_CANCEL_ALL = 5,
};

enum nvme_tcp_recv_state {
Expand Down Expand Up @@ -205,6 +208,7 @@ static struct workqueue_struct *nvme_tcp_wq;
static const struct blk_mq_ops nvme_tcp_mq_ops;
static const struct blk_mq_ops nvme_tcp_admin_mq_ops;
static int nvme_tcp_try_send(struct nvme_tcp_queue *queue);
static void nvme_tcp_complete_rq(struct request *rq);

static inline struct nvme_tcp_ctrl *to_tcp_ctrl(struct nvme_ctrl *ctrl)
{
Expand Down Expand Up @@ -617,7 +621,7 @@ static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
req->status = cqe->status;

if (!nvme_try_complete_req(rq, req->status, cqe->result))
nvme_complete_rq(rq);
nvme_tcp_complete_rq(rq);
queue->nr_cqe++;

return 0;
Expand Down Expand Up @@ -817,7 +821,7 @@ static inline void nvme_tcp_end_request(struct request *rq, u16 status)
union nvme_result res = {};

if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
nvme_complete_rq(rq);
nvme_tcp_complete_rq(rq);
}

static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
Expand Down Expand Up @@ -1833,6 +1837,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
goto err_init_connect;

set_bit(NVME_TCP_Q_ALLOCATED, &queue->flags);
clear_bit(NVME_TCP_Q_CANCEL_ONE, &queue->flags);
clear_bit(NVME_TCP_Q_CANCEL_ALL, &queue->flags);

return 0;

Expand Down Expand Up @@ -2551,10 +2557,12 @@ static void nvme_tcp_complete_timed_out(struct request *rq)
static enum blk_eh_timer_return nvme_tcp_timeout(struct request *rq)
{
struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
struct nvme_tcp_cmd_pdu *pdu = nvme_tcp_req_cmd_pdu(req);
struct nvme_command *cmd = &pdu->cmd;
int qid = nvme_tcp_queue_id(req->queue);
struct nvme_tcp_queue *queue = req->queue;
struct nvme_ctrl *ctrl = &queue->ctrl->ctrl;
int qid = nvme_tcp_queue_id(queue);
int error, action;

dev_warn(ctrl->device,
"I/O tag %d (%04x) type %d opcode %#x (%s) QID %d timeout\n",
Expand All @@ -2579,10 +2587,39 @@ static enum blk_eh_timer_return nvme_tcp_timeout(struct request *rq)
return BLK_EH_DONE;
}

if (!req->aborted) {
if (!nvme_io_command_supported(ctrl, nvme_cmd_cancel) || !qid)
goto err_recovery;

if (!test_and_set_bit(NVME_TCP_Q_CANCEL_ONE, &queue->flags)) {
action = NVME_CANCEL_ACTION_SINGLE_CMD;
} else if (!test_and_set_bit(NVME_TCP_Q_CANCEL_ALL,
&queue->flags)) {
action = NVME_CANCEL_ACTION_MUL_CMD;
} else {
/* No free reserved commands.
* this means a "multiple commands" cancel
* is currently under execution and this request
* is likely to be canceled. Mark this
* request as aborted and reset the timer.
*/
goto abort;
}

error = nvme_submit_cancel_req(ctrl, rq, qid, action);
if (error)
goto err_recovery;

abort:
req->aborted = true;
return BLK_EH_RESET_TIMER;
}

/*
* LIVE state should trigger the normal error recovery which will
* handle completing this request.
*/
err_recovery:
nvme_tcp_error_recovery(ctrl);
return BLK_EH_RESET_TIMER;
}
Expand Down Expand Up @@ -2627,6 +2664,7 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
req->pdu_len = 0;
req->pdu_sent = 0;
req->h2cdata_left = 0;
req->aborted = false;
req->data_len = blk_rq_nr_phys_segments(rq) ?
blk_rq_payload_bytes(rq) : 0;
req->curr_bio = rq->bio;
Expand Down Expand Up @@ -2742,10 +2780,24 @@ static int nvme_tcp_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
return len;
}

static void nvme_tcp_complete_rq(struct request *rq)
{
struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
struct nvme_tcp_queue *queue = req->queue;
bool is_cancel = nvme_is_cancel(req->req.cmd);

nvme_complete_rq(rq);

if (is_cancel) {
if (!test_and_clear_bit(NVME_TCP_Q_CANCEL_ALL, &queue->flags))
clear_bit(NVME_TCP_Q_CANCEL_ONE, &queue->flags);
}
}

static const struct blk_mq_ops nvme_tcp_mq_ops = {
.queue_rq = nvme_tcp_queue_rq,
.commit_rqs = nvme_tcp_commit_rqs,
.complete = nvme_complete_rq,
.complete = nvme_tcp_complete_rq,
.init_request = nvme_tcp_init_request,
.exit_request = nvme_tcp_exit_request,
.init_hctx = nvme_tcp_init_hctx,
Expand Down
Loading