|
|
|
@ -313,11 +313,70 @@ void iscsi_free_mgmt_task(struct iscsi_conn *conn,
|
|
|
|
|
list_del_init(&mtask->running);
|
|
|
|
|
if (conn->login_mtask == mtask)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (conn->ping_mtask == mtask)
|
|
|
|
|
conn->ping_mtask = NULL;
|
|
|
|
|
__kfifo_put(conn->session->mgmtpool.queue,
|
|
|
|
|
(void*)&mtask, sizeof(void*));
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
|
|
|
|
|
|
|
|
|
|
static struct iscsi_mgmt_task *
|
|
|
|
|
__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
|
|
|
|
char *data, uint32_t data_size)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_session *session = conn->session;
|
|
|
|
|
struct iscsi_mgmt_task *mtask;
|
|
|
|
|
|
|
|
|
|
if (session->state == ISCSI_STATE_TERMINATE)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
|
|
|
|
|
hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
|
|
|
|
|
/*
|
|
|
|
|
* Login and Text are sent serially, in
|
|
|
|
|
* request-followed-by-response sequence.
|
|
|
|
|
* Same mtask can be used. Same ITT must be used.
|
|
|
|
|
* Note that login_mtask is preallocated at conn_create().
|
|
|
|
|
*/
|
|
|
|
|
mtask = conn->login_mtask;
|
|
|
|
|
else {
|
|
|
|
|
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
|
|
|
|
|
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
|
|
|
|
|
|
|
|
|
|
if (!__kfifo_get(session->mgmtpool.queue,
|
|
|
|
|
(void*)&mtask, sizeof(void*)))
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data_size) {
|
|
|
|
|
memcpy(mtask->data, data, data_size);
|
|
|
|
|
mtask->data_count = data_size;
|
|
|
|
|
} else
|
|
|
|
|
mtask->data_count = 0;
|
|
|
|
|
|
|
|
|
|
memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
|
|
|
|
|
INIT_LIST_HEAD(&mtask->running);
|
|
|
|
|
list_add_tail(&mtask->running, &conn->mgmtqueue);
|
|
|
|
|
return mtask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
|
|
|
|
|
char *data, uint32_t data_size)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_conn *conn = cls_conn->dd_data;
|
|
|
|
|
struct iscsi_session *session = conn->session;
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&session->lock);
|
|
|
|
|
if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
|
|
|
|
|
err = -EPERM;
|
|
|
|
|
spin_unlock_bh(&session->lock);
|
|
|
|
|
scsi_queue_work(session->host, &conn->xmitwork);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* iscsi_cmd_rsp - SCSI Command Response processing
|
|
|
|
|
* @conn: iscsi connection
|
|
|
|
@ -409,6 +468,39 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
|
|
|
|
|
wake_up(&conn->ehwait);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_nopout hdr;
|
|
|
|
|
struct iscsi_mgmt_task *mtask;
|
|
|
|
|
|
|
|
|
|
if (!rhdr && conn->ping_mtask)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
memset(&hdr, 0, sizeof(struct iscsi_nopout));
|
|
|
|
|
hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
|
|
|
|
|
hdr.flags = ISCSI_FLAG_CMD_FINAL;
|
|
|
|
|
|
|
|
|
|
if (rhdr) {
|
|
|
|
|
memcpy(hdr.lun, rhdr->lun, 8);
|
|
|
|
|
hdr.ttt = rhdr->ttt;
|
|
|
|
|
hdr.itt = RESERVED_ITT;
|
|
|
|
|
} else
|
|
|
|
|
hdr.ttt = RESERVED_ITT;
|
|
|
|
|
|
|
|
|
|
mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
|
|
|
|
|
if (!mtask) {
|
|
|
|
|
printk(KERN_ERR "Could not send nopout\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* only track our nops */
|
|
|
|
|
if (!rhdr) {
|
|
|
|
|
conn->ping_mtask = mtask;
|
|
|
|
|
conn->last_ping = jiffies;
|
|
|
|
|
}
|
|
|
|
|
scsi_queue_work(conn->session->host, &conn->xmitwork);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
|
|
|
|
char *data, int datalen)
|
|
|
|
|
{
|
|
|
|
@ -453,6 +545,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
|
|
|
|
struct iscsi_mgmt_task *mtask;
|
|
|
|
|
uint32_t itt;
|
|
|
|
|
|
|
|
|
|
conn->last_recv = jiffies;
|
|
|
|
|
if (hdr->itt != RESERVED_ITT)
|
|
|
|
|
itt = get_itt(hdr->itt);
|
|
|
|
|
else
|
|
|
|
@ -520,14 +613,22 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
|
|
|
|
iscsi_free_mgmt_task(conn, mtask);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_OP_NOOP_IN:
|
|
|
|
|
if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
|
|
|
|
|
if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) ||
|
|
|
|
|
datalen) {
|
|
|
|
|
rc = ISCSI_ERR_PROTO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
|
|
|
|
|
|
|
|
|
|
if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
|
|
|
|
|
rc = ISCSI_ERR_CONN_FAILED;
|
|
|
|
|
if (conn->ping_mtask != mtask) {
|
|
|
|
|
/*
|
|
|
|
|
* If this is not in response to one of our
|
|
|
|
|
* nops then it must be from userspace.
|
|
|
|
|
*/
|
|
|
|
|
if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
|
|
|
|
|
datalen))
|
|
|
|
|
rc = ISCSI_ERR_CONN_FAILED;
|
|
|
|
|
}
|
|
|
|
|
iscsi_free_mgmt_task(conn, mtask);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
@ -547,8 +648,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
|
|
|
|
if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
|
|
|
|
|
rc = ISCSI_ERR_CONN_FAILED;
|
|
|
|
|
iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_OP_REJECT:
|
|
|
|
|
rc = iscsi_handle_reject(conn, hdr, data, datalen);
|
|
|
|
@ -1003,62 +1103,6 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
|
|
|
|
|
|
|
|
|
|
static struct iscsi_mgmt_task *
|
|
|
|
|
__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
|
|
|
|
char *data, uint32_t data_size)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_session *session = conn->session;
|
|
|
|
|
struct iscsi_mgmt_task *mtask;
|
|
|
|
|
|
|
|
|
|
if (session->state == ISCSI_STATE_TERMINATE)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
|
|
|
|
|
hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
|
|
|
|
|
/*
|
|
|
|
|
* Login and Text are sent serially, in
|
|
|
|
|
* request-followed-by-response sequence.
|
|
|
|
|
* Same mtask can be used. Same ITT must be used.
|
|
|
|
|
* Note that login_mtask is preallocated at conn_create().
|
|
|
|
|
*/
|
|
|
|
|
mtask = conn->login_mtask;
|
|
|
|
|
else {
|
|
|
|
|
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
|
|
|
|
|
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
|
|
|
|
|
|
|
|
|
|
if (!__kfifo_get(session->mgmtpool.queue,
|
|
|
|
|
(void*)&mtask, sizeof(void*)))
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data_size) {
|
|
|
|
|
memcpy(mtask->data, data, data_size);
|
|
|
|
|
mtask->data_count = data_size;
|
|
|
|
|
} else
|
|
|
|
|
mtask->data_count = 0;
|
|
|
|
|
|
|
|
|
|
memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
|
|
|
|
|
INIT_LIST_HEAD(&mtask->running);
|
|
|
|
|
list_add_tail(&mtask->running, &conn->mgmtqueue);
|
|
|
|
|
return mtask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
|
|
|
|
|
char *data, uint32_t data_size)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_conn *conn = cls_conn->dd_data;
|
|
|
|
|
struct iscsi_session *session = conn->session;
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&session->lock);
|
|
|
|
|
if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
|
|
|
|
|
err = -EPERM;
|
|
|
|
|
spin_unlock_bh(&session->lock);
|
|
|
|
|
scsi_queue_work(session->host, &conn->xmitwork);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
|
|
|
|
|
|
|
|
|
|
void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_session *session = class_to_transport_session(cls_session);
|
|
|
|
@ -1134,7 +1178,8 @@ static void iscsi_tmf_timedout(unsigned long data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
|
|
|
|
|
struct iscsi_tm *hdr, int age)
|
|
|
|
|
struct iscsi_tm *hdr, int age,
|
|
|
|
|
int timeout)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_session *session = conn->session;
|
|
|
|
|
struct iscsi_mgmt_task *mtask;
|
|
|
|
@ -1149,7 +1194,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
|
|
|
|
|
return -EPERM;
|
|
|
|
|
}
|
|
|
|
|
conn->tmfcmd_pdus_cnt++;
|
|
|
|
|
conn->tmf_timer.expires = 30 * HZ + jiffies;
|
|
|
|
|
conn->tmf_timer.expires = timeout * HZ + jiffies;
|
|
|
|
|
conn->tmf_timer.function = iscsi_tmf_timedout;
|
|
|
|
|
conn->tmf_timer.data = (unsigned long)conn;
|
|
|
|
|
add_timer(&conn->tmf_timer);
|
|
|
|
@ -1233,6 +1278,106 @@ static void iscsi_start_tx(struct iscsi_conn *conn)
|
|
|
|
|
scsi_queue_work(conn->session->host, &conn->xmitwork);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_cls_session *cls_session;
|
|
|
|
|
struct iscsi_session *session;
|
|
|
|
|
struct iscsi_conn *conn;
|
|
|
|
|
enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
|
|
|
|
|
|
|
|
|
|
cls_session = starget_to_session(scsi_target(scmd->device));
|
|
|
|
|
session = class_to_transport_session(cls_session);
|
|
|
|
|
|
|
|
|
|
debug_scsi("scsi cmd %p timedout\n", scmd);
|
|
|
|
|
|
|
|
|
|
spin_lock(&session->lock);
|
|
|
|
|
if (session->state != ISCSI_STATE_LOGGED_IN) {
|
|
|
|
|
/*
|
|
|
|
|
* We are probably in the middle of iscsi recovery so let
|
|
|
|
|
* that complete and handle the error.
|
|
|
|
|
*/
|
|
|
|
|
rc = EH_RESET_TIMER;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conn = session->leadconn;
|
|
|
|
|
if (!conn) {
|
|
|
|
|
/* In the middle of shuting down */
|
|
|
|
|
rc = EH_RESET_TIMER;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!conn->recv_timeout && !conn->ping_timeout)
|
|
|
|
|
goto done;
|
|
|
|
|
/*
|
|
|
|
|
* if the ping timedout then we are in the middle of cleaning up
|
|
|
|
|
* and can let the iscsi eh handle it
|
|
|
|
|
*/
|
|
|
|
|
if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
|
|
|
|
|
(conn->ping_timeout * HZ), jiffies))
|
|
|
|
|
rc = EH_RESET_TIMER;
|
|
|
|
|
/*
|
|
|
|
|
* if we are about to check the transport then give the command
|
|
|
|
|
* more time
|
|
|
|
|
*/
|
|
|
|
|
if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
|
|
|
|
|
jiffies))
|
|
|
|
|
rc = EH_RESET_TIMER;
|
|
|
|
|
/* if in the middle of checking the transport then give us more time */
|
|
|
|
|
if (conn->ping_mtask)
|
|
|
|
|
rc = EH_RESET_TIMER;
|
|
|
|
|
done:
|
|
|
|
|
spin_unlock(&session->lock);
|
|
|
|
|
debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void iscsi_check_transport_timeouts(unsigned long data)
|
|
|
|
|
{
|
|
|
|
|
struct iscsi_conn *conn = (struct iscsi_conn *)data;
|
|
|
|
|
struct iscsi_session *session = conn->session;
|
|
|
|
|
unsigned long timeout, next_timeout = 0, last_recv;
|
|
|
|
|
|
|
|
|
|
spin_lock(&session->lock);
|
|
|
|
|
if (session->state != ISCSI_STATE_LOGGED_IN)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
timeout = conn->recv_timeout;
|
|
|
|
|
if (!timeout)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
timeout *= HZ;
|
|
|
|
|
last_recv = conn->last_recv;
|
|
|
|
|
if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
|
|
|
|
|
jiffies)) {
|
|
|
|
|
printk(KERN_ERR "ping timeout of %d secs expired, "
|
|
|
|
|
"last rx %lu, last ping %lu, now %lu\n",
|
|
|
|
|
conn->ping_timeout, last_recv,
|
|
|
|
|
conn->last_ping, jiffies);
|
|
|
|
|
spin_unlock(&session->lock);
|
|
|
|
|
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (time_before_eq(last_recv + timeout, jiffies)) {
|
|
|
|
|
if (time_before_eq(conn->last_ping, last_recv)) {
|
|
|
|
|
/* send a ping to try to provoke some traffic */
|
|
|
|
|
debug_scsi("Sending nopout as ping on conn %p\n", conn);
|
|
|
|
|
iscsi_send_nopout(conn, NULL);
|
|
|
|
|
}
|
|
|
|
|
next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
|
|
|
|
|
} else {
|
|
|
|
|
next_timeout = last_recv + timeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (next_timeout) {
|
|
|
|
|
debug_scsi("Setting next tmo %lu\n", next_timeout);
|
|
|
|
|
mod_timer(&conn->transport_timer, next_timeout);
|
|
|
|
|
}
|
|
|
|
|
done:
|
|
|
|
|
spin_unlock(&session->lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask,
|
|
|
|
|
struct iscsi_tm *hdr)
|
|
|
|
|
{
|
|
|
|
@ -1304,7 +1449,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
|
|
|
|
|
hdr = &conn->tmhdr;
|
|
|
|
|
iscsi_prep_abort_task_pdu(ctask, hdr);
|
|
|
|
|
|
|
|
|
|
if (iscsi_exec_task_mgmt_fn(conn, hdr, age)) {
|
|
|
|
|
if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
|
|
|
|
|
rc = FAILED;
|
|
|
|
|
goto failed;
|
|
|
|
|
}
|
|
|
|
@ -1365,7 +1510,7 @@ static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
|
|
|
|
|
hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
|
|
|
|
|
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
|
|
|
|
|
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
|
|
|
|
|
hdr->rtt = ISCSI_RESERVED_TAG;
|
|
|
|
|
hdr->rtt = RESERVED_ITT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int iscsi_eh_device_reset(struct scsi_cmnd *sc)
|
|
|
|
@ -1396,7 +1541,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
|
|
|
|
|
hdr = &conn->tmhdr;
|
|
|
|
|
iscsi_prep_lun_reset_pdu(sc, hdr);
|
|
|
|
|
|
|
|
|
|
if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age)) {
|
|
|
|
|
if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
|
|
|
|
|
session->lu_reset_timeout)) {
|
|
|
|
|
rc = FAILED;
|
|
|
|
|
goto unlock;
|
|
|
|
|
}
|
|
|
|
@ -1572,12 +1718,14 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
|
|
|
|
|
shost->max_cmd_len = iscsit->max_cmd_len;
|
|
|
|
|
shost->transportt = scsit;
|
|
|
|
|
shost->transportt->create_work_queue = 1;
|
|
|
|
|
shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
|
|
|
|
|
*hostno = shost->host_no;
|
|
|
|
|
|
|
|
|
|
session = iscsi_hostdata(shost->hostdata);
|
|
|
|
|
memset(session, 0, sizeof(struct iscsi_session));
|
|
|
|
|
session->host = shost;
|
|
|
|
|
session->state = ISCSI_STATE_FREE;
|
|
|
|
|
session->fast_abort = 1;
|
|
|
|
|
session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
|
|
|
|
|
session->cmds_max = cmds_max;
|
|
|
|
|
session->queued_cmdsn = session->cmdsn = initial_cmdsn;
|
|
|
|
@ -1708,6 +1856,11 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
|
|
|
|
|
conn->id = conn_idx;
|
|
|
|
|
conn->exp_statsn = 0;
|
|
|
|
|
conn->tmf_state = TMF_INITIAL;
|
|
|
|
|
|
|
|
|
|
init_timer(&conn->transport_timer);
|
|
|
|
|
conn->transport_timer.data = (unsigned long)conn;
|
|
|
|
|
conn->transport_timer.function = iscsi_check_transport_timeouts;
|
|
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&conn->run_list);
|
|
|
|
|
INIT_LIST_HEAD(&conn->mgmt_run_list);
|
|
|
|
|
INIT_LIST_HEAD(&conn->mgmtqueue);
|
|
|
|
@ -1757,6 +1910,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
|
|
|
|
|
struct iscsi_session *session = conn->session;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
del_timer_sync(&conn->transport_timer);
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&session->lock);
|
|
|
|
|
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
|
|
|
|
|
if (session->leadconn == conn) {
|
|
|
|
@ -1823,11 +1978,29 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (conn->ping_timeout && !conn->recv_timeout) {
|
|
|
|
|
printk(KERN_ERR "iscsi: invalid recv timeout of zero "
|
|
|
|
|
"Using 5 seconds\n.");
|
|
|
|
|
conn->recv_timeout = 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (conn->recv_timeout && !conn->ping_timeout) {
|
|
|
|
|
printk(KERN_ERR "iscsi: invalid ping timeout of zero "
|
|
|
|
|
"Using 5 seconds.\n");
|
|
|
|
|
conn->ping_timeout = 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&session->lock);
|
|
|
|
|
conn->c_stage = ISCSI_CONN_STARTED;
|
|
|
|
|
session->state = ISCSI_STATE_LOGGED_IN;
|
|
|
|
|
session->queued_cmdsn = session->cmdsn;
|
|
|
|
|
|
|
|
|
|
conn->last_recv = jiffies;
|
|
|
|
|
conn->last_ping = jiffies;
|
|
|
|
|
if (conn->recv_timeout && conn->ping_timeout)
|
|
|
|
|
mod_timer(&conn->transport_timer,
|
|
|
|
|
jiffies + (conn->recv_timeout * HZ));
|
|
|
|
|
|
|
|
|
|
switch(conn->stop_stage) {
|
|
|
|
|
case STOP_CONN_RECOVER:
|
|
|
|
|
/*
|
|
|
|
@ -1879,6 +2052,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
|
|
|
|
|
{
|
|
|
|
|
int old_stop_stage;
|
|
|
|
|
|
|
|
|
|
del_timer_sync(&conn->transport_timer);
|
|
|
|
|
|
|
|
|
|
mutex_lock(&session->eh_mutex);
|
|
|
|
|
spin_lock_bh(&session->lock);
|
|
|
|
|
if (conn->stop_stage == STOP_CONN_TERM) {
|
|
|
|
@ -1993,6 +2168,18 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
|
|
|
|
case ISCSI_PARAM_FAST_ABORT:
|
|
|
|
|
sscanf(buf, "%d", &session->fast_abort);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_ABORT_TMO:
|
|
|
|
|
sscanf(buf, "%d", &session->abort_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_LU_RESET_TMO:
|
|
|
|
|
sscanf(buf, "%d", &session->lu_reset_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_PING_TMO:
|
|
|
|
|
sscanf(buf, "%d", &conn->ping_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_RECV_TMO:
|
|
|
|
|
sscanf(buf, "%d", &conn->recv_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_MAX_RECV_DLENGTH:
|
|
|
|
|
sscanf(buf, "%d", &conn->max_recv_dlength);
|
|
|
|
|
break;
|
|
|
|
@ -2110,6 +2297,12 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
|
|
|
|
|
case ISCSI_PARAM_FAST_ABORT:
|
|
|
|
|
len = sprintf(buf, "%d\n", session->fast_abort);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_ABORT_TMO:
|
|
|
|
|
len = sprintf(buf, "%d\n", session->abort_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_LU_RESET_TMO:
|
|
|
|
|
len = sprintf(buf, "%d\n", session->lu_reset_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_INITIAL_R2T_EN:
|
|
|
|
|
len = sprintf(buf, "%d\n", session->initial_r2t_en);
|
|
|
|
|
break;
|
|
|
|
@ -2167,6 +2360,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
switch(param) {
|
|
|
|
|
case ISCSI_PARAM_PING_TMO:
|
|
|
|
|
len = sprintf(buf, "%u\n", conn->ping_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_RECV_TMO:
|
|
|
|
|
len = sprintf(buf, "%u\n", conn->recv_timeout);
|
|
|
|
|
break;
|
|
|
|
|
case ISCSI_PARAM_MAX_RECV_DLENGTH:
|
|
|
|
|
len = sprintf(buf, "%u\n", conn->max_recv_dlength);
|
|
|
|
|
break;
|
|
|
|
|