diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 5b332d9f87fc..81096c83b238 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -147,6 +147,11 @@ struct nvme_tcp_queue { __le32 exp_ddgst; __le32 recv_ddgst; + /* Aborts for admin queue, cancel commands + * for io queues (if target supports them). + */ + struct list_head abrt_list; + struct page_frag_cache pf_cache; void (*state_change)(struct sock *); @@ -1318,6 +1323,28 @@ static int nvme_tcp_alloc_async_req(struct nvme_tcp_ctrl *ctrl) return 0; } +static nvme_tcp_request *nvme_tcp_alloc_abort_req(struct nvme_tcp_ctrl *ctrl) +{ + struct nvme_tcp_queue *queue = &ctrl->queues[0]; + u8 hdgst = nvme_tcp_hdgst_len(queue); + struct nvme_tcp_request *abrt; + + abrt = kzalloc(sizeof(*abrt), GFP_KERNEL); + if (!abrt) + return NULL; + + abrt->pdu = page_frag_alloc(&queue->pf_cache, + sizeof(struct nvme_tcp_cmd_pdu) + hdgst, + GFP_KERNEL | GFP_ZERO); + if (!abrt->pdu) { + kfree(abrt); + return NULL; + } + + list_add_tail(&queue->abrt_list); + return abrt; +} + static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid) { struct page *page; @@ -1517,6 +1544,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid) queue->ctrl = ctrl; init_llist_head(&queue->req_list); INIT_LIST_HEAD(&queue->send_list); + INIT_LIST_HEAD(&queue->abrt_list); mutex_init(&queue->send_mutex); INIT_WORK(&queue->io_work, nvme_tcp_io_work); @@ -2252,6 +2280,42 @@ static void nvme_tcp_submit_async_event(struct nvme_ctrl *arg) nvme_tcp_queue_request(&ctrl->async_req, true, true); } +static int nvme_tcp_submit_abort_req(struct nvme_ctrl *arg, + int cid, int sqid) +{ + struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(arg); + struct nvme_tcp_queue *queue = &ctrl->queues[0]; + struct nvme_tcp_request *abrt; + struct nvme_tcp_cmd_pdu *pdu; + struct nvme_command *cmd; + u8 hdgst = nvme_tcp_hdgst_len(queue); + + abrt = nvme_tcp_alloc_abort_req(ctrl); + if (!abrt) + return -ENOMEM; + + pdu = abrt->pdu; + cmd = &pdu->cmd; + + pdu->hdr.type = nvme_tcp_cmd; + if (queue->hdr_digest) + pdu->hdr.flags |= NVME_TCP_F_HDGST; + pdu->hdr.hlen = sizeof(*pdu); + pdu->hdr.plen = cpu_to_le32(pud->hdr.hlen + hdgst); + cmd->abort.opcode = nvme_admin_abort_cmd; + cmd->abort.command_id = NVME_AQ_BLK_MQ_DEPTH; /* FIXME */ + cmd->abort.cid = cid; + cmd->abort.sqid = cpu_to_le32(sqid); + nvme_tcp_set_sg_null(cmd); + + abrt->state = NVME_TCP_SEND_CMD_PDU; + abrt->offset = 0; + abrt->curr_bio = NULL; + abrt->data_len = 0; + + nvme_tcp_queue_request(abrt, true, true); +} + static void nvme_tcp_complete_timed_out(struct request *rq) { struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);