diff options
Diffstat (limited to 'drivers/scsi/qedi/qedi_iscsi.c')
-rw-r--r-- | drivers/scsi/qedi/qedi_iscsi.c | 105 |
1 files changed, 68 insertions, 37 deletions
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 08c05403cd72..97f83760da88 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -330,12 +330,22 @@ free_conn: void qedi_mark_device_missing(struct iscsi_cls_session *cls_session) { - iscsi_block_session(cls_session); + struct iscsi_session *session = cls_session->dd_data; + struct qedi_conn *qedi_conn = session->leadconn->dd_data; + + spin_lock_bh(&session->frwd_lock); + set_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags); + spin_unlock_bh(&session->frwd_lock); } void qedi_mark_device_available(struct iscsi_cls_session *cls_session) { - iscsi_unblock_session(cls_session); + struct iscsi_session *session = cls_session->dd_data; + struct qedi_conn *qedi_conn = session->leadconn->dd_data; + + spin_lock_bh(&session->frwd_lock); + clear_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags); + spin_unlock_bh(&session->frwd_lock); } static int qedi_bind_conn_to_iscsi_cid(struct qedi_ctx *qedi, @@ -377,6 +387,7 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session, struct qedi_ctx *qedi = iscsi_host_priv(shost); struct qedi_endpoint *qedi_ep; struct iscsi_endpoint *ep; + int rc = 0; ep = iscsi_lookup_endpoint(transport_fd); if (!ep) @@ -384,11 +395,16 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session, qedi_ep = ep->dd_data; if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) || - (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) - return -EINVAL; + (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) { + rc = -EINVAL; + goto put_ep; + } + + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) { + rc = -EINVAL; + goto put_ep; + } - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) - return -EINVAL; qedi_ep->conn = qedi_conn; qedi_conn->ep = qedi_ep; @@ -398,13 +414,18 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session, qedi_conn->cmd_cleanup_req = 0; qedi_conn->cmd_cleanup_cmpl = 0; - if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) - return -EINVAL; + if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) { + rc = -EINVAL; + goto put_ep; + } + spin_lock_init(&qedi_conn->tmf_work_lock); INIT_LIST_HEAD(&qedi_conn->tmf_work_list); init_waitqueue_head(&qedi_conn->wait_queue); - return 0; +put_ep: + iscsi_put_endpoint(ep); + return rc; } static int qedi_iscsi_update_conn(struct qedi_ctx *qedi, @@ -582,7 +603,11 @@ static int qedi_conn_start(struct iscsi_cls_conn *cls_conn) goto start_err; } - clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + spin_lock(&qedi_conn->tmf_work_lock); + qedi_conn->fw_cleanup_works = 0; + qedi_conn->ep_disconnect_starting = false; + spin_unlock(&qedi_conn->tmf_work_lock); + qedi_conn->abrt_conn = 0; rval = iscsi_conn_start(cls_conn); @@ -742,7 +767,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); @@ -772,7 +797,6 @@ static int qedi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) } cmd->conn = conn->dd_data; - cmd->scsi_cmd = NULL; return qedi_iscsi_send_generic_request(task); } @@ -783,9 +807,16 @@ static int qedi_task_xmit(struct iscsi_task *task) struct qedi_cmd *cmd = task->dd_data; struct scsi_cmnd *sc = task->sc; + /* Clear now so in cleanup_task we know it didn't make it */ + cmd->scsi_cmd = NULL; + cmd->task_id = U16_MAX; + if (test_bit(QEDI_IN_SHUTDOWN, &qedi_conn->qedi->flags)) return -ENODEV; + if (test_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags)) + return -EACCES; + cmd->state = 0; cmd->task = NULL; cmd->use_slowpath = false; @@ -988,12 +1019,10 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep) { struct qedi_endpoint *qedi_ep; struct qedi_conn *qedi_conn = NULL; - struct iscsi_conn *conn = NULL; struct qedi_ctx *qedi; int ret = 0; int wait_delay; int abrt_conn = 0; - int count = 10; wait_delay = 60 * HZ + DEF_MAX_RT_TIME; qedi_ep = ep->dd_data; @@ -1007,17 +1036,21 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep) if (qedi_ep->conn) { qedi_conn = qedi_ep->conn; - conn = qedi_conn->cls_conn->dd_data; - iscsi_suspend_queue(conn); abrt_conn = qedi_conn->abrt_conn; - while (count--) { - if (!test_bit(QEDI_CONN_FW_CLEANUP, - &qedi_conn->flags)) { - break; - } + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "cid=0x%x qedi_ep=%p waiting for %d tmfs\n", + qedi_ep->iscsi_cid, qedi_ep, + qedi_conn->fw_cleanup_works); + + spin_lock(&qedi_conn->tmf_work_lock); + qedi_conn->ep_disconnect_starting = true; + while (qedi_conn->fw_cleanup_works > 0) { + spin_unlock(&qedi_conn->tmf_work_lock); msleep(1000); + spin_lock(&qedi_conn->tmf_work_lock); } + spin_unlock(&qedi_conn->tmf_work_lock); if (test_bit(QEDI_IN_RECOVERY, &qedi->flags)) { if (qedi_do_not_recover) { @@ -1383,13 +1416,24 @@ static umode_t qedi_attr_is_visible(int param_type, int param) static void qedi_cleanup_task(struct iscsi_task *task) { - if (!task->sc || task->state == ISCSI_TASK_PENDING) { + struct qedi_cmd *cmd; + + if (task->state == ISCSI_TASK_PENDING) { QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n", refcount_read(&task->refcount)); return; } - qedi_iscsi_unmap_sg_list(task->dd_data); + if (task->sc) + qedi_iscsi_unmap_sg_list(task->dd_data); + + cmd = task->dd_data; + if (cmd->task_id != U16_MAX) + qedi_clear_task_idx(iscsi_host_priv(task->conn->session->host), + cmd->task_id); + + cmd->task_id = U16_MAX; + cmd->scsi_cmd = NULL; } struct iscsi_transport qedi_iscsi_transport = { @@ -1401,6 +1445,7 @@ struct iscsi_transport qedi_iscsi_transport = { .destroy_session = qedi_session_destroy, .create_conn = qedi_conn_create, .bind_conn = qedi_conn_bind, + .unbind_conn = iscsi_conn_unbind, .start_conn = qedi_conn_start, .stop_conn = iscsi_conn_stop, .destroy_conn = qedi_conn_destroy, @@ -1614,20 +1659,6 @@ void qedi_process_iscsi_error(struct qedi_endpoint *ep, qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); } -void qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess) -{ - struct iscsi_session *session = cls_sess->dd_data; - struct iscsi_conn *conn = session->leadconn; - struct qedi_conn *qedi_conn = conn->dd_data; - - if (iscsi_is_session_online(cls_sess)) - qedi_ep_disconnect(qedi_conn->iscsi_ep); - - qedi_conn_destroy(qedi_conn->cls_conn); - - qedi_session_destroy(cls_sess); -} - void qedi_process_tcp_error(struct qedi_endpoint *ep, struct iscsi_eqe_data *data) { |