diff options
-rw-r--r-- | etc/iscsid.conf | 19 | ||||
-rw-r--r-- | include/iscsi_if.h | 11 | ||||
-rw-r--r-- | kernel/iscsi_tcp.c | 4 | ||||
-rw-r--r-- | kernel/libiscsi.c | 331 | ||||
-rw-r--r-- | kernel/libiscsi.h | 8 | ||||
-rw-r--r-- | kernel/scsi_transport_iscsi.c | 4 | ||||
-rw-r--r-- | usr/config.h | 5 | ||||
-rw-r--r-- | usr/discovery.c | 7 | ||||
-rw-r--r-- | usr/idbm.c | 24 | ||||
-rw-r--r-- | usr/initiator.c | 58 | ||||
-rw-r--r-- | usr/initiator.h | 7 | ||||
-rw-r--r-- | usr/iscsi_settings.h | 4 | ||||
-rw-r--r-- | usr/netlink.c | 1 | ||||
-rw-r--r-- | usr/util.c | 9 |
14 files changed, 361 insertions, 131 deletions
diff --git a/etc/iscsid.conf b/etc/iscsid.conf index e950e3f..ea05c89 100644 --- a/etc/iscsid.conf +++ b/etc/iscsid.conf @@ -83,18 +83,14 @@ node.conn[0].timeo.login_timeout = 15 # The value is in seconds and the default is 15 seconds. node.conn[0].timeo.logout_timeout = 15 -# To specify the intervale to send iSCSI Nop-outs as pings -# to the target edit this the line. -# The value is in seconds and the default is 10 seconds. -node.conn[0].timeo.noop_out_interval = 10 +# Time interval to wait for on connection before sending a ping. +node.conn[0].timeo.noop_out_interval = 5 # To specify the time to wait for a Nop-out response before failing # the connection, edit this line. Failing the connection will # cause IO to be failed back to the SCSI layer. If using dm-multipath # this will cause the IO to be failed to the multipath layer. -# The value is in seconds and the default is 15 seconds. -node.conn[0].timeo.noop_out_timeout = 15 - +node.conn[0].timeo.noop_out_timeout = 5 #****** # Retry @@ -212,11 +208,10 @@ discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 # Some targets like IET prefer after an initiator has sent a task # management function like an ABORT TASK or LOGICAL UNIT RESET, that # it does not respond to PDUs like R2Ts. To enable this behavior uncomment -# the following line (The default behavior is No): -# node.session.iscsi.FastAbort = Yes +# the following line (The default behavior is Yes): +node.session.iscsi.FastAbort = Yes # Some targets like Equalogic prefer that after an initiator has sent # a task management function like an ABORT TASK or LOGICAL UNIT RESET, that -# it continue to respond to R2Ts. To enable this uncomment this line (This -# is the default behavior): -node.session.iscsi.FastAbort = No +# it continue to respond to R2Ts. To enable this uncomment this line +# node.session.iscsi.FastAbort = No diff --git a/include/iscsi_if.h b/include/iscsi_if.h index 7820294..dff4f29 100644 --- a/include/iscsi_if.h +++ b/include/iscsi_if.h @@ -244,6 +244,12 @@ enum iscsi_param { ISCSI_PARAM_PASSWORD_IN, ISCSI_PARAM_FAST_ABORT, + ISCSI_PARAM_ABORT_TMO, + ISCSI_PARAM_LU_RESET_TMO, + ISCSI_PARAM_HOST_RESET_TMO, + + ISCSI_PARAM_PING_TMO, + ISCSI_PARAM_RECV_TMO, /* must always be last */ ISCSI_PARAM_MAX, }; @@ -275,6 +281,11 @@ enum iscsi_param { #define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD) #define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN) #define ISCSI_FAST_ABORT (1 << ISCSI_PARAM_FAST_ABORT) +#define ISCSI_ABORT_TMO (1 << ISCSI_PARAM_ABORT_TMO) +#define ISCSI_LU_RESET_TMO (1 << ISCSI_PARAM_LU_RESET_TMO) +#define ISCSI_HOST_RESET_TMO (1 << ISCSI_PARAM_HOST_RESET_TMO) +#define ISCSI_PING_TMO (1 << ISCSI_PARAM_PING_TMO) +#define ISCSI_RECV_TMO (1 << ISCSI_PARAM_RECV_TMO) /* iSCSI HBA params */ enum iscsi_host_param { diff --git a/kernel/iscsi_tcp.c b/kernel/iscsi_tcp.c index 2b84855..a51c564 100644 --- a/kernel/iscsi_tcp.c +++ b/kernel/iscsi_tcp.c @@ -2301,7 +2301,9 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | - ISCSI_FAST_ABORT, + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_LU_RESET_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME | ISCSI_HOST_NETDEV_NAME, diff --git a/kernel/libiscsi.c b/kernel/libiscsi.c index 7f94987..5f695b6 100644 --- a/kernel/libiscsi.c +++ b/kernel/libiscsi.c @@ -283,11 +283,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 @@ -380,6 +439,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) { @@ -424,6 +516,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 @@ -491,14 +584,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: @@ -518,8 +619,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); @@ -971,62 +1071,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); @@ -1102,7 +1146,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; @@ -1117,7 +1162,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); @@ -1201,6 +1246,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) { @@ -1272,7 +1417,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; } @@ -1333,7 +1478,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) @@ -1364,7 +1509,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; } @@ -1535,12 +1681,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; @@ -1671,6 +1819,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); @@ -1720,6 +1873,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) { @@ -1786,11 +1941,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: /* @@ -1842,6 +2015,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) { @@ -1956,6 +2131,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; @@ -2073,6 +2260,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; @@ -2130,6 +2323,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; diff --git a/kernel/libiscsi.h b/kernel/libiscsi.h index b4a082f..d02c55f 100644 --- a/kernel/libiscsi.h +++ b/kernel/libiscsi.h @@ -133,6 +133,12 @@ struct iscsi_conn { * conn_stop() flag: stop to recover, stop to terminate */ int stop_stage; + struct timer_list transport_timer; + unsigned long last_recv; + unsigned long last_ping; + int ping_timeout; + int recv_timeout; + struct iscsi_mgmt_task *ping_mtask; /* iSCSI connection-wide sequencing */ uint32_t exp_statsn; @@ -223,6 +229,8 @@ struct iscsi_session { uint32_t queued_cmdsn; /* configuration */ + int abort_timeout; + int lu_reset_timeout; int initial_r2t_en; unsigned max_r2t; int imm_data_en; diff --git a/kernel/scsi_transport_iscsi.c b/kernel/scsi_transport_iscsi.c index 078ea9b..56ba5c2 100644 --- a/kernel/scsi_transport_iscsi.c +++ b/kernel/scsi_transport_iscsi.c @@ -1211,6 +1211,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); +iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO); +iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO); #define iscsi_cdev_to_session(_cdev) \ iscsi_dev_to_session(_cdev->dev) @@ -1446,6 +1448,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); + SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO); + SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO); BUG_ON(count > ISCSI_CONN_ATTRS); priv->conn_attrs[count] = NULL; diff --git a/usr/config.h b/usr/config.h index 864aee7..e767d6d 100644 --- a/usr/config.h +++ b/usr/config.h @@ -66,8 +66,6 @@ struct iscsi_connection_timeout_config { int logout_timeout; int auth_timeout; int active_timeout; - int idle_timeout; - int ping_timeout; int noop_out_interval; int noop_out_timeout; }; @@ -86,7 +84,8 @@ struct iscsi_session_timeout_config { */ struct iscsi_error_timeout_config { int abort_timeout; - int reset_timeout; + int host_reset_timeout; + int lu_reset_timeout; }; /* all TCP options go in this structure. diff --git a/usr/discovery.c b/usr/discovery.c index a10b0ea..6e010bd 100644 --- a/usr/discovery.c +++ b/usr/discovery.c @@ -548,7 +548,6 @@ init_new_session(struct iscsi_sendtargets_config *config) session->conn[0].login_timeout = config->conn_timeo.login_timeout; session->conn[0].auth_timeout = config->conn_timeo.auth_timeout; session->conn[0].active_timeout = config->conn_timeo.active_timeout; - session->conn[0].idle_timeout = config->conn_timeo.idle_timeout; session->conn[0].hdrdgst_en = ISCSI_DIGEST_NONE; session->conn[0].datadgst_en = ISCSI_DIGEST_NONE; @@ -879,11 +878,9 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, goto free_sendtargets; } - log_debug(4, "discovery timeouts: login %d, reopen_cnt %d, auth %d, " - "active %d, idle %d, ping %d", + log_debug(4, "discovery timeouts: login %d, reopen_cnt %d, auth %d.", session->conn[0].login_timeout, session->reopen_cnt, - session->conn[0].auth_timeout, session->conn[0].active_timeout, - session->conn[0].idle_timeout, session->conn[0].ping_timeout); + session->conn[0].auth_timeout); /* setup authentication variables for the session*/ rc = setup_authentication(session, drec, config); @@ -230,11 +230,8 @@ idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) u.sendtargets.conn_timeo.auth_timeout, IDBM_SHOW, num); __recinfo_int("discovery.sendtargets.timeo.active_timeout",ri,r, - u.sendtargets.conn_timeo.active_timeout, - IDBM_SHOW, num); - __recinfo_int("discovery.sendtargets.timeo.idle_timeout", ri, r, - u.sendtargets.conn_timeo.idle_timeout, - IDBM_SHOW, num); + u.sendtargets.conn_timeo.active_timeout, + IDBM_SHOW, num); __recinfo_int("discovery.sendtargets.iscsi.MaxRecvDataSegmentLength", ri, r, u.sendtargets.iscsi.MaxRecvDataSegmentLength, IDBM_SHOW, num); @@ -298,8 +295,11 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) __recinfo_int("node.session.err_timeo.abort_timeout", ri, r, session.err_timeo.abort_timeout, IDBM_SHOW, num); - __recinfo_int("node.session.err_timeo.reset_timeout", ri, r, - session.err_timeo.reset_timeout, + __recinfo_int("node.session.err_timeo.lu_reset_timeout", ri, r, + session.err_timeo.lu_reset_timeout, + IDBM_SHOW, num); + __recinfo_int("node.session.err_timeo.host_reset_timeout", ri, r, + session.err_timeo.host_reset_timeout, IDBM_SHOW, num); __recinfo_int_o2("node.session.iscsi.FastAbort", ri, r, session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes", num); @@ -349,15 +349,6 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) sprintf(key, "node.conn[%d].timeo.auth_timeout", i); __recinfo_int(key, ri, r, conn[i].timeo.auth_timeout, IDBM_SHOW, num); - sprintf(key, "node.conn[%d].timeo.active_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.active_timeout, - IDBM_SHOW, num); - sprintf(key, "node.conn[%d].timeo.idle_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.idle_timeout, - IDBM_SHOW, num); - sprintf(key, "node.conn[%d].timeo.ping_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.ping_timeout, - IDBM_SHOW, num); sprintf(key, "node.conn[%d].timeo.noop_out_interval", i); __recinfo_int(key, ri, r, conn[i].timeo.noop_out_interval, @@ -474,7 +465,6 @@ idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type) rec->u.sendtargets.conn_timeo.login_timeout=15; rec->u.sendtargets.conn_timeo.auth_timeout = 45; rec->u.sendtargets.conn_timeo.active_timeout=30; - rec->u.sendtargets.conn_timeo.idle_timeout = 60; rec->u.sendtargets.iscsi.MaxRecvDataSegmentLength = DEF_INI_DISC_MAX_RECV_SEG_LEN; } else if (type == DISCOVERY_TYPE_SLP) { diff --git a/usr/initiator.c b/usr/initiator.c index 70ac050..84a0f86 100644 --- a/usr/initiator.c +++ b/usr/initiator.c @@ -431,6 +431,8 @@ __session_conn_create(iscsi_session_t *session, int cid) conn->login_timeout = DEF_LOGIN_TIMEO; } + conn->auth_timeout = conn_rec->timeo.auth_timeout; + /* noop-out setting */ conn->noop_out_interval = conn_rec->timeo.noop_out_interval; conn->noop_out_timeout = conn_rec->timeo.noop_out_timeout; @@ -445,18 +447,9 @@ __session_conn_create(iscsi_session_t *session, int cid) log_error("Invalid timeo.noop_out_interval. Must be greater " "than zero. Using default %d.\n", DEF_NOOP_OUT_INTERVAL); - conn->noop_out_timeout = DEF_NOOP_OUT_INTERVAL; + conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL; } - /* - * currently not used (leftover from linux-iscsi which we - * may do one day) - */ - conn->auth_timeout = conn_rec->timeo.auth_timeout; - conn->active_timeout = conn_rec->timeo.active_timeout; - conn->idle_timeout = conn_rec->timeo.idle_timeout; - conn->ping_timeout = conn_rec->timeo.ping_timeout; - iscsi_copy_operational_params(conn); /* TCP options */ @@ -1084,7 +1077,7 @@ mgmt_ipc_err_e iscsi_host_set_param(int host_no, int param, char *value) return MGMT_IPC_OK; } -#define MAX_SESSION_PARAMS 25 +#define MAX_SESSION_PARAMS 30 #define MAX_HOST_PARAMS 3 static void @@ -1245,13 +1238,32 @@ setup_full_feature_phase(iscsi_conn_t *conn) .value = &session->fast_abort, .type = ISCSI_INT, .conn_only = 0, + }, { + .param = ISCSI_PARAM_ABORT_TMO, + .value = &session->abort_timeout, + .type = ISCSI_INT, + .conn_only = 0, + }, { + .param = ISCSI_PARAM_LU_RESET_TMO, + .value = &session->lu_reset_timeout, + .type = ISCSI_INT, + .conn_only = 0, + }, { + .param = ISCSI_PARAM_HOST_RESET_TMO, + .value = &session->host_reset_timeout, + .type = ISCSI_INT, + .conn_only = 0, + }, { + .param = ISCSI_PARAM_PING_TMO, + .value = &conn->noop_out_timeout, + .type = ISCSI_INT, + .conn_only = 1, + }, { + .param = ISCSI_PARAM_RECV_TMO, + .value = &conn->noop_out_interval, + .type = ISCSI_INT, + .conn_only = 1, }, - /* - * FIXME: set these timeouts via set_param() API - * - * rec->session.timeo - * rec->session.err_timeo - */ }; /* almost! entered full-feature phase */ @@ -1304,6 +1316,11 @@ setup_full_feature_phase(iscsi_conn_t *conn) return; } + /* older kernels may not support nop handling in kernel */ + if (rc == -ENOSYS && + conntbl[i].param == ISCSI_PARAM_PING_TMO) + conn->userspace_nop = 1; + print_param_value(conntbl[i].param, conntbl[i].value, conntbl[i].type); } @@ -1358,7 +1375,7 @@ setup_full_feature_phase(iscsi_conn_t *conn) session->r_stage = R_STAGE_NO_CHANGE; /* noop_out */ - if (conn->noop_out_interval) { + if (conn->userspace_nop && conn->noop_out_interval) { actor_timer(&conn->nop_out_timer, conn->noop_out_interval*1000, conn_send_nop_out, conn); log_debug(3, "noop out timer %p start\n", @@ -1455,6 +1472,11 @@ static void iscsi_logout(void *data) static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr) { + if (!conn->userspace_nop) { + log_error("Got nop in, but kernel supports nop handling."); + return; + } + if (hdr->ttt == ISCSI_RESERVED_TAG) { /* noop out rsp */ actor_delete(&conn->nop_out_timer); diff --git a/usr/initiator.h b/usr/initiator.h index 9bfc43d..968ee13 100644 --- a/usr/initiator.h +++ b/usr/initiator.h @@ -107,6 +107,7 @@ typedef struct iscsi_conn { char data[ISCSI_DEF_MAX_RECV_SEG_LEN]; char host[NI_MAXHOST]; /* scratch */ iscsi_conn_state_e state; + int userspace_nop; actor_t login_timer; actor_t nop_out_timer; @@ -139,8 +140,6 @@ typedef struct iscsi_conn { int logout_timeout; int auth_timeout; int active_timeout; - int idle_timeout; - int ping_timeout; int noop_out_interval; int noop_out_timeout; @@ -233,7 +232,9 @@ typedef struct iscsi_session { iscsi_session_r_stage_e r_stage; uint32_t replacement_timeout; - int unbinding; + int host_reset_timeout; + int lu_reset_timeout; + int abort_timeout; /* sync up fields */ queue_task_t *sync_qtask; diff --git a/usr/iscsi_settings.h b/usr/iscsi_settings.h index 4bb7064..107a4f7 100644 --- a/usr/iscsi_settings.h +++ b/usr/iscsi_settings.h @@ -9,6 +9,10 @@ #define DEF_NOOP_OUT_TIMEO 15 #define DEF_REPLACEMENT_TIMEO 120 +#define DEF_ABORT_TIMEO 15 +#define DEF_LU_RESET_TIMEO 30 +#define DEF_HOST_RESET_TIMEO 60 + /* q depths */ #define CMDS_MAX 128 #define QUEUE_DEPTH 32 diff --git a/usr/netlink.c b/usr/netlink.c index 5eabccf..9f21bc9 100644 --- a/usr/netlink.c +++ b/usr/netlink.c @@ -868,7 +868,6 @@ static int ctldev_handle(void) { int rc, ev_size; struct iscsi_uevent *ev; - struct iscsi_transport *t; iscsi_session_t *session = NULL; iscsi_conn_t *conn = NULL; char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; @@ -190,8 +190,9 @@ void idbm_node_setup_defaults(node_rec_t *rec) rec->session.auth.authmethod = 0; rec->session.auth.password_length = 0; rec->session.auth.password_in_length = 0; - rec->session.err_timeo.abort_timeout = 10; - rec->session.err_timeo.reset_timeout = 30; + rec->session.err_timeo.abort_timeout = DEF_ABORT_TIMEO; + rec->session.err_timeo.lu_reset_timeout = DEF_LU_RESET_TIMEO; + rec->session.err_timeo.host_reset_timeout = DEF_HOST_RESET_TIMEO; rec->session.timeo.replacement_timeout = DEF_REPLACEMENT_TIMEO; rec->session.iscsi.InitialR2T = 0; rec->session.iscsi.ImmediateData = 1; @@ -202,6 +203,7 @@ void idbm_node_setup_defaults(node_rec_t *rec) rec->session.iscsi.MaxConnections = 1; rec->session.iscsi.MaxOutstandingR2T = 1; rec->session.iscsi.ERL = 0; + rec->session.iscsi.FastAbort = 1; for (i=0; i<ISCSI_CONN_MAX; i++) { rec->conn[i].startup = 0; @@ -211,9 +213,6 @@ void idbm_node_setup_defaults(node_rec_t *rec) rec->conn[i].timeo.login_timeout= DEF_LOGIN_TIMEO; rec->conn[i].timeo.logout_timeout= DEF_LOGOUT_TIMEO; rec->conn[i].timeo.auth_timeout = 45; - rec->conn[i].timeo.active_timeout=5; - rec->conn[i].timeo.idle_timeout = 60; - rec->conn[i].timeo.ping_timeout = 5; rec->conn[i].timeo.noop_out_interval = DEF_NOOP_OUT_INTERVAL; rec->conn[i].timeo.noop_out_timeout = DEF_NOOP_OUT_TIMEO; |