This has qedi do it's fw cleanup from the eh abort callout then call into libiscsi to do the protocol/libiscsi cleanup. Signed-off-by: Mike Christie <michael.christie@xxxxxxxxxx> --- drivers/scsi/qedi/qedi_fw.c | 216 ++++++++++----------------------- drivers/scsi/qedi/qedi_gbl.h | 4 +- drivers/scsi/qedi/qedi_iscsi.c | 48 +++++++- drivers/scsi/qedi/qedi_iscsi.h | 1 + 4 files changed, 113 insertions(+), 156 deletions(-) diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index 440ddd2309f1..d8e10e8d3d08 100644 --- a/drivers/scsi/qedi/qedi_fw.c +++ b/drivers/scsi/qedi/qedi_fw.c @@ -14,9 +14,6 @@ #include "qedi_fw_iscsi.h" #include "qedi_fw_scsi.h" -static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, - struct iscsi_task *mtask); - void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd) { struct scsi_cmnd *sc = cmd->scsi_cmd; @@ -739,7 +736,6 @@ static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi, static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, struct iscsi_cqe_solicited *cqe, - struct iscsi_task *task, struct iscsi_conn *conn) { struct qedi_work_map *work, *work_tmp; @@ -752,8 +748,7 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, u32 iscsi_cid; struct qedi_conn *qedi_conn; struct qedi_cmd *dbg_cmd; - struct iscsi_task *mtask; - struct iscsi_tm *tmf_hdr = NULL; + struct iscsi_task *task; iscsi_cid = cqe->conn_id; qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; @@ -777,8 +772,7 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, WARN_ON(1); } found = 1; - mtask = qedi_cmd->task; - tmf_hdr = (struct iscsi_tm *)mtask->hdr; + task = work->task; rtid = work->rtid; list_del_init(&work->list); @@ -790,49 +784,30 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, if (found) { QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, - "TMF work, cqe->tid=0x%x, tmf flags=0x%x, cid=0x%x\n", - proto_itt, tmf_hdr->flags, qedi_conn->iscsi_conn_id); - - if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == - ISCSI_TM_FUNC_ABORT_TASK) { - spin_lock_bh(&conn->session->back_lock); - - protoitt = build_itt(get_itt(tmf_hdr->rtt), - conn->session->age); - task = iscsi_itt_to_task(conn, protoitt); + "TMF work, cqe->tid=0x%x, cid=0x%x\n", + proto_itt, qedi_conn->iscsi_conn_id); - spin_unlock_bh(&conn->session->back_lock); + dbg_cmd = task->dd_data; - if (!task) { - QEDI_NOTICE(&qedi->dbg_ctx, - "IO task completed, tmf rtt=0x%x, cid=0x%x\n", - get_itt(tmf_hdr->rtt), - qedi_conn->iscsi_conn_id); - return; - } - - dbg_cmd = task->dd_data; - - QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, - "Abort tmf rtt=0x%x, i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n", - get_itt(tmf_hdr->rtt), get_itt(task->itt), - dbg_cmd->task_id, qedi_conn->iscsi_conn_id); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "Abort i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n", + get_itt(task->itt), dbg_cmd->task_id, + qedi_conn->iscsi_conn_id); - if (qedi_cmd->state == CLEANUP_WAIT_FAILED) - qedi_cmd->state = CLEANUP_RECV; + if (qedi_cmd->state == CLEANUP_WAIT_FAILED) + qedi_cmd->state = CLEANUP_RECV; - qedi_clear_task_idx(qedi_conn->qedi, rtid); + qedi_clear_task_idx(qedi_conn->qedi, rtid); - spin_lock(&qedi_conn->list_lock); - if (likely(dbg_cmd->io_cmd_in_list)) { - dbg_cmd->io_cmd_in_list = false; - list_del_init(&dbg_cmd->io_cmd); - qedi_conn->active_cmd_count--; - } - spin_unlock(&qedi_conn->list_lock); - qedi_cmd->state = CLEANUP_RECV; - wake_up_interruptible(&qedi_conn->wait_queue); + spin_lock(&qedi_conn->list_lock); + if (likely(dbg_cmd->io_cmd_in_list)) { + dbg_cmd->io_cmd_in_list = false; + list_del_init(&dbg_cmd->io_cmd); + qedi_conn->active_cmd_count--; } + spin_unlock(&qedi_conn->list_lock); + qedi_cmd->state = CLEANUP_RECV; + wake_up_interruptible(&qedi_conn->wait_queue); } else if (qedi_conn->cmd_cleanup_req > 0) { spin_lock_bh(&conn->session->back_lock); qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt); @@ -959,8 +934,7 @@ void qedi_fp_process_cqes(struct qedi_work *work) goto exit_fp_process; case ISCSI_CQE_TYPE_TASK_CLEANUP: QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "CleanUp CqE\n"); - qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, task, - conn); + qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, conn); goto exit_fp_process; default: QEDI_ERR(&qedi->dbg_ctx, "Error cqe.\n"); @@ -1368,59 +1342,41 @@ static int qedi_wait_for_cleanup_request(struct qedi_ctx *qedi, return 0; } -static void qedi_tmf_work(struct work_struct *work) +int qedi_fw_cleanup_cmd(struct iscsi_task *ctask) { - struct qedi_cmd *qedi_cmd = - container_of(work, struct qedi_cmd, tmf_work); - struct qedi_conn *qedi_conn = qedi_cmd->conn; + struct iscsi_conn *conn = ctask->conn; + struct qedi_conn *qedi_conn = conn->dd_data; struct qedi_ctx *qedi = qedi_conn->qedi; - struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; - struct qedi_work_map *list_work = NULL; - struct iscsi_task *mtask; - struct qedi_cmd *cmd; - struct iscsi_task *ctask; - struct iscsi_tm *tmf_hdr; + struct qedi_work_map *list_work; + struct qedi_cmd *cmd, qedi_cmd; s16 rval = 0; - s16 tid = 0; - - mtask = qedi_cmd->task; - tmf_hdr = (struct iscsi_tm *)mtask->hdr; - set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); - - ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt); - if (!ctask || !ctask->sc) { - QEDI_ERR(&qedi->dbg_ctx, "Task already completed\n"); - goto abort_ret; - } - cmd = (struct qedi_cmd *)ctask->dd_data; + cmd = ctask->dd_data; QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, - "Abort tmf rtt=0x%x, cmd itt=0x%x, cmd tid=0x%x, cid=0x%x\n", - get_itt(tmf_hdr->rtt), get_itt(ctask->itt), cmd->task_id, - qedi_conn->iscsi_conn_id); + "abort tmf cmd itt=0x%x, cmd tid=0x%x, cid=0x%x\n", + get_itt(ctask->itt), cmd->task_id, qedi_conn->iscsi_conn_id); - if (qedi_do_not_recover) { - QEDI_ERR(&qedi->dbg_ctx, "DONT SEND CLEANUP/ABORT %d\n", - qedi_do_not_recover); - goto abort_ret; - } - - list_work = kzalloc(sizeof(*list_work), GFP_ATOMIC); + list_work = kzalloc(sizeof(*list_work), GFP_NOIO); if (!list_work) { - QEDI_ERR(&qedi->dbg_ctx, "Memory allocation failed\n"); - goto abort_ret; + QEDI_ERR(&qedi->dbg_ctx, "memory allocation failed\n"); + return -ENOMEM; } - qedi_cmd->type = TYPEIO; - list_work->qedi_cmd = qedi_cmd; + memset(&qedi_cmd, 0, sizeof(struct qedi_cmd)); + qedi_cmd.conn = qedi_conn; + qedi_cmd.type = TYPEIO; + qedi_cmd.list_tmf_work = list_work; + qedi_cmd.state = CLEANUP_WAIT; + + INIT_LIST_HEAD(&list_work->list); + list_work->task = ctask; + list_work->qedi_cmd = &qedi_cmd; list_work->rtid = cmd->task_id; list_work->state = QEDI_WORK_SCHEDULED; - qedi_cmd->list_tmf_work = list_work; QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, - "Queue tmf work=%p, list node=%p, cid=0x%x, tmf flags=0x%x\n", - list_work->ptr_tmf_work, list_work, qedi_conn->iscsi_conn_id, - tmf_hdr->flags); + "queue tmf work=%p, list node=%p, cid=0x%x\n", + list_work->ptr_tmf_work, list_work, qedi_conn->iscsi_conn_id); spin_lock_bh(&qedi_conn->tmf_work_lock); list_add_tail(&list_work->list, &qedi_conn->tmf_work_list); @@ -1428,34 +1384,21 @@ static void qedi_tmf_work(struct work_struct *work) qedi_iscsi_cleanup_task(ctask, false); - rval = qedi_wait_for_cleanup_request(qedi, qedi_conn, ctask, qedi_cmd, + rval = qedi_wait_for_cleanup_request(qedi, qedi_conn, ctask, &qedi_cmd, list_work); if (rval == -1) { QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, - "FW cleanup got escalated, cid=0x%x\n", + "fw cleanup got escalated, cid=0x%x\n", qedi_conn->iscsi_conn_id); - goto ldel_exit; + goto force_cleanup; } - tid = qedi_get_task_idx(qedi); - if (tid == -1) { - QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n", - qedi_conn->iscsi_conn_id); - goto ldel_exit; - } - - qedi_cmd->task_id = tid; - qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task); - -abort_ret: - clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); - return; + return 0; -ldel_exit: +force_cleanup: spin_lock_bh(&qedi_conn->tmf_work_lock); - if (!qedi_cmd->list_tmf_work) { + if (!qedi_cmd.list_tmf_work) { list_del_init(&list_work->list); - qedi_cmd->list_tmf_work = NULL; kfree(list_work); } spin_unlock_bh(&qedi_conn->tmf_work_lock); @@ -1468,11 +1411,10 @@ static void qedi_tmf_work(struct work_struct *work) } spin_unlock(&qedi_conn->list_lock); - clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + return -1; } -static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, - struct iscsi_task *mtask) +int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask) { struct iscsi_tmf_request_hdr tmf_pdu_header; struct iscsi_task_params task_params; @@ -1491,6 +1433,19 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, tmf_hdr = (struct iscsi_tm *)mtask->hdr; qedi_cmd = (struct qedi_cmd *)mtask->dd_data; + + switch (tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) { + case ISCSI_TM_FUNC_ABORT_TASK: + case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: + case ISCSI_TM_FUNC_TARGET_WARM_RESET: + case ISCSI_TM_FUNC_TARGET_COLD_RESET: + break; + default: + QEDI_ERR(&qedi->dbg_ctx, "Invalid tmf, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + return -EINVAL; + } + ep = qedi_conn->ep; if (!ep) return -ENODEV; @@ -1566,49 +1521,6 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, return 0; } -int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn, - struct iscsi_task *mtask) -{ - struct qedi_ctx *qedi = qedi_conn->qedi; - struct iscsi_tm *tmf_hdr; - struct qedi_cmd *qedi_cmd = (struct qedi_cmd *)mtask->dd_data; - s16 tid = 0; - - tmf_hdr = (struct iscsi_tm *)mtask->hdr; - qedi_cmd->task = mtask; - - /* If abort task then schedule the work and return */ - if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == - ISCSI_TM_FUNC_ABORT_TASK) { - qedi_cmd->state = CLEANUP_WAIT; - INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_work); - queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work); - - } else if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == - ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) || - ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == - ISCSI_TM_FUNC_TARGET_WARM_RESET) || - ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == - ISCSI_TM_FUNC_TARGET_COLD_RESET)) { - tid = qedi_get_task_idx(qedi); - if (tid == -1) { - QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n", - qedi_conn->iscsi_conn_id); - return -1; - } - qedi_cmd->task_id = tid; - - qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task); - - } else { - QEDI_ERR(&qedi->dbg_ctx, "Invalid tmf, cid=0x%x\n", - qedi_conn->iscsi_conn_id); - return -1; - } - - return 0; -} - int qedi_send_iscsi_text(struct qedi_conn *qedi_conn, struct iscsi_task *task) { diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h index 116645c08c71..a3b72e7ff9d9 100644 --- a/drivers/scsi/qedi/qedi_gbl.h +++ b/drivers/scsi/qedi/qedi_gbl.h @@ -31,8 +31,7 @@ int qedi_send_iscsi_login(struct qedi_conn *qedi_conn, struct iscsi_task *task); int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn, struct iscsi_task *task); -int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn, - struct iscsi_task *mtask); +int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask); int qedi_send_iscsi_text(struct qedi_conn *qedi_conn, struct iscsi_task *task); int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn, @@ -60,6 +59,7 @@ void qedi_mark_device_available(struct iscsi_cls_session *cls_session); void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu); int qedi_recover_all_conns(struct qedi_ctx *qedi); void qedi_fp_process_cqes(struct qedi_work *work); +int qedi_fw_cleanup_cmd(struct iscsi_task *ctask); int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn, struct iscsi_task *task, bool in_recovery); diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 36e81eb567b2..0f3704c4c985 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -43,13 +43,57 @@ static int qedi_eh_host_reset(struct scsi_cmnd *cmd) return qedi_recover_all_conns(qedi); } +static int qedi_eh_abort(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *shost = cmd->device->host; + struct qedi_ctx *qedi = iscsi_host_priv(shost); + struct iscsi_cls_session *cls_session; + struct iscsi_session *session; + struct qedi_conn *qedi_conn; + struct iscsi_task *task; + int rc; + + cls_session = starget_to_session(scsi_target(cmd->device)); + session = cls_session->dd_data; + + if (qedi_do_not_recover) { + QEDI_ERR(&qedi->dbg_ctx, "dont send cleanup/abort %d\n", + qedi_do_not_recover); + return FAILED; + } + + /* check if we raced, task just got cleaned up under us */ + spin_lock_bh(&session->back_lock); + task = (struct iscsi_task *)cmd->SCp.ptr; + if (!task || !task->sc) { + spin_unlock_bh(&session->back_lock); + return SUCCESS; + } + + __iscsi_get_task(task); + spin_unlock_bh(&session->back_lock); + + qedi_conn = task->conn->dd_data; + set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + + rc = qedi_fw_cleanup_cmd(task); + + iscsi_put_task(task); + clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + + if (rc) + return FAILED; + + return iscsi_eh_abort(cmd); +} + struct scsi_host_template qedi_host_template = { .module = THIS_MODULE, .name = "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver", .proc_name = QEDI_MODULE_NAME, .queuecommand = iscsi_queuecommand, .eh_timed_out = iscsi_eh_cmd_timed_out, - .eh_abort_handler = iscsi_eh_abort, + .eh_abort_handler = qedi_eh_abort, .eh_device_reset_handler = iscsi_eh_device_reset, .eh_target_reset_handler = iscsi_eh_recover_target, .eh_host_reset_handler = qedi_eh_host_reset, @@ -746,7 +790,7 @@ static int qedi_iscsi_send_generic_request(struct iscsi_task *task) rc = qedi_send_iscsi_logout(qedi_conn, task); break; case ISCSI_OP_SCSI_TMFUNC: - rc = qedi_iscsi_abort_work(qedi_conn, task); + rc = qedi_send_iscsi_tmf(qedi_conn, task); break; case ISCSI_OP_TEXT: rc = qedi_send_iscsi_text(qedi_conn, task); diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h index 39dc27c85e3c..8a96c1fde630 100644 --- a/drivers/scsi/qedi/qedi_iscsi.h +++ b/drivers/scsi/qedi/qedi_iscsi.h @@ -212,6 +212,7 @@ struct qedi_cmd { struct qedi_work_map { struct list_head list; struct qedi_cmd *qedi_cmd; + struct iscsi_task *task; int rtid; int state; -- 2.25.1