summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libiscsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r--drivers/scsi/libiscsi.c153
1 files changed, 83 insertions, 70 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index d43f909a022c..b7a2b9ad3a97 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -37,9 +37,6 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/libiscsi.h>
-static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
- int err);
-
struct iscsi_session *
class_to_transport_session(struct iscsi_cls_session *cls_session)
{
@@ -274,6 +271,53 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
iscsi_complete_command(ctask);
}
+/*
+ * session lock must be held
+ */
+static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ int err)
+{
+ struct scsi_cmnd *sc;
+
+ sc = ctask->sc;
+ if (!sc)
+ return;
+
+ if (ctask->state == ISCSI_TASK_PENDING)
+ /*
+ * cmd never made it to the xmit thread, so we should not count
+ * the cmd in the sequencing
+ */
+ conn->session->queued_cmdsn--;
+ else
+ conn->session->tt->cleanup_cmd_task(conn, ctask);
+
+ sc->result = err;
+ scsi_set_resid(sc, scsi_bufflen(sc));
+ if (conn->ctask == ctask)
+ conn->ctask = NULL;
+ /* release ref from queuecommand */
+ __iscsi_put_ctask(ctask);
+}
+
+/**
+ * iscsi_free_mgmt_task - return mgmt task back to pool
+ * @conn: iscsi connection
+ * @mtask: mtask
+ *
+ * Must be called with session lock.
+ */
+void iscsi_free_mgmt_task(struct iscsi_conn *conn,
+ struct iscsi_mgmt_task *mtask)
+{
+ list_del_init(&mtask->running);
+ if (conn->login_mtask == mtask)
+ return;
+ __kfifo_put(conn->session->mgmtpool.queue,
+ (void*)&mtask, sizeof(void*));
+}
+EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
+
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
@@ -464,10 +508,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
*/
if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
- list_del_init(&mtask->running);
- if (conn->login_mtask != mtask)
- __kfifo_put(session->mgmtpool.queue,
- (void*)&mtask, sizeof(void*));
+ iscsi_free_mgmt_task(conn, mtask);
break;
case ISCSI_OP_SCSI_TMFUNC_RSP:
if (datalen) {
@@ -476,6 +517,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
}
iscsi_tmf_rsp(conn, hdr);
+ iscsi_free_mgmt_task(conn, mtask);
break;
case ISCSI_OP_NOOP_IN:
if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
@@ -486,9 +528,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
- list_del_init(&mtask->running);
- __kfifo_put(session->mgmtpool.queue,
- (void*)&mtask, sizeof(void*));
+ iscsi_free_mgmt_task(conn, mtask);
break;
default:
rc = ISCSI_ERR_BAD_OPCODE;
@@ -650,14 +690,12 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
static int iscsi_xmit_mtask(struct iscsi_conn *conn)
{
struct iscsi_hdr *hdr = conn->mtask->hdr;
- int rc, was_logout = 0;
+ int rc;
+ if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
+ conn->session->state = ISCSI_STATE_LOGGING_OUT;
spin_unlock_bh(&conn->session->lock);
- if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
- conn->session->state = ISCSI_STATE_IN_RECOVERY;
- iscsi_block_session(session_to_cls(conn->session));
- was_logout = 1;
- }
+
rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
spin_lock_bh(&conn->session->lock);
if (rc)
@@ -665,11 +703,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
/* done with this in-progress mtask */
conn->mtask = NULL;
-
- if (was_logout) {
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- return -ENODATA;
- }
return 0;
}
@@ -763,6 +796,12 @@ check_mgmt:
while (!list_empty(&conn->mgmtqueue)) {
conn->mtask = list_entry(conn->mgmtqueue.next,
struct iscsi_mgmt_task, running);
+ if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+ iscsi_free_mgmt_task(conn, conn->mtask);
+ conn->mtask = NULL;
+ continue;
+ }
+
iscsi_prep_mtask(conn, conn->mtask);
list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
rc = iscsi_xmit_mtask(conn);
@@ -777,6 +816,10 @@ check_mgmt:
conn->ctask = list_entry(conn->xmitqueue.next,
struct iscsi_cmd_task, running);
+ if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+ fail_command(conn, conn->ctask, DID_NO_CONNECT << 16);
+ continue;
+ }
if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
fail_command(conn, conn->ctask, DID_ABORT << 16);
continue;
@@ -800,6 +843,12 @@ check_mgmt:
if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
break;
+ /*
+ * we always do fastlogout - conn stop code will clean up.
+ */
+ if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
+ break;
+
conn->ctask = list_entry(conn->requeue.next,
struct iscsi_cmd_task, running);
conn->ctask->state = ISCSI_TASK_RUNNING;
@@ -842,6 +891,7 @@ enum {
FAILURE_SESSION_TERMINATE,
FAILURE_SESSION_IN_RECOVERY,
FAILURE_SESSION_RECOVERY_TIMEOUT,
+ FAILURE_SESSION_LOGGING_OUT,
};
int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
@@ -879,12 +929,19 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
goto reject;
}
- if (session->state == ISCSI_STATE_RECOVERY_FAILED)
+ switch (session->state) {
+ case ISCSI_STATE_RECOVERY_FAILED:
reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
- else if (session->state == ISCSI_STATE_TERMINATE)
+ break;
+ case ISCSI_STATE_TERMINATE:
reason = FAILURE_SESSION_TERMINATE;
- else
+ break;
+ case ISCSI_STATE_LOGGING_OUT:
+ reason = FAILURE_SESSION_LOGGING_OUT;
+ break;
+ default:
reason = FAILURE_SESSION_FREED;
+ }
goto fault;
}
@@ -1120,45 +1177,10 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
if (age != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
return -ENOTCONN;
-
- if (!list_empty(&mtask->running)) {
- list_del_init(&mtask->running);
- __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
- sizeof(void*));
- }
return 0;
}
/*
- * session lock must be held
- */
-static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
- int err)
-{
- struct scsi_cmnd *sc;
-
- sc = ctask->sc;
- if (!sc)
- return;
-
- if (ctask->state == ISCSI_TASK_PENDING)
- /*
- * cmd never made it to the xmit thread, so we should not count
- * the cmd in the sequencing
- */
- conn->session->queued_cmdsn--;
- else
- conn->session->tt->cleanup_cmd_task(conn, ctask);
-
- sc->result = err;
- scsi_set_resid(sc, scsi_bufflen(sc));
- if (conn->ctask == ctask)
- conn->ctask = NULL;
- /* release ref from queuecommand */
- __iscsi_put_ctask(ctask);
-}
-
-/*
* Fail commands. session lock held and recv side suspended and xmit
* thread flushed
*/
@@ -1837,22 +1859,13 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
/* handle pending */
list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
- list_del_init(&mtask->running);
- if (mtask == conn->login_mtask)
- continue;
- __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
- sizeof(void*));
+ iscsi_free_mgmt_task(conn, mtask);
}
/* handle running */
list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
- list_del_init(&mtask->running);
-
- if (mtask == conn->login_mtask)
- continue;
- __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
- sizeof(void*));
+ iscsi_free_mgmt_task(conn, mtask);
}
conn->mtask = NULL;
OpenPOWER on IntegriCloud