|
|
|
@ -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,44 +1177,9 @@ 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;
|
|
|
|
|