iSCSI 사용중 아래와 같은 에러메세지가 발생하였으며, 어떤 메세지인지 확인이 필요하였다.
Jun 22 16:30:48 hostname iscsid: Kernel reported iSCSI connection 3:0 error (1022 - ISCSI_ERR_NOP_TIMEDOUT: A NOP has timed out) state (3)
Jun 22 16:31:49 hostname kernel: kernel: connection3:0: ping timeout of 5 secs expired, recv timeout 5, last rx 36174282912, last ping 36174287936, now 36174292992
Jun 22 16:31:50 hostname kernel: [3011710.723336] connection3:0: detected conn error (1022)
session->id 의 값은 3, conn->id 의 값은 0 error 는 1022 이며 error code 내용은 ISCSI_ERR_NOP_TIMEDOUT: A NOP has timed out conn->state는 3 이라는 값을 확인 할수 있다.
open-iscsi/usr/initiator.c
static void session_conn_error(void *data)
{
struct iscsi_ev_context *ev_context = data;
enum iscsi_err error = *(enum iscsi_err *)ev_context->data;
iscsi_conn_t *conn = ev_context->conn;
iscsi_session_t *session = conn->session;
int sid = session->id;
log_warning("Kernel reported iSCSI connection %d:%d error (%d - %s) "
"state (%d)", session->id, conn->id, error,
kern_err_code_to_string(error), conn->state);
iscsi_ev_context_put(ev_context);
switch (error) {
case ISCSI_ERR_INVALID_HOST:
if (session_conn_shutdown(conn, NULL, ISCSI_SUCCESS))
log_error("BUG: Could not shutdown session:%d.", sid);
break;
default:
__conn_error_handle(session, conn);
}
}
/include/scsi/iscsi_if.h 에 명시된 내용과 같이 iSCSI 에러는 1000 부터 시작이며 ISCSI_ERR_NOP_TIMEDOUT 는 1000+22=1022 즉 ISCSI_ERR_BASE + ISCSI_ERR_NOP_TIMEDOUT 를 뜻하는 것을 알수 있다.
state의 값은iscsi_conn_state에 정의된 ISCSI_CONN_STATE_LOGGED_IN이며 ISCSI initiator이 target에 로그인할때 발생된 에러를 의미한다.
/include/scsi/iscsi_if.h
<snip>
#define ISCSI_ERR_BASE 1000
<snip>
enum iscsi_err {
ISCSI_OK = 0,
ISCSI_ERR_DATASN = ISCSI_ERR_BASE + 1,
ISCSI_ERR_DATA_OFFSET = ISCSI_ERR_BASE + 2,
ISCSI_ERR_MAX_CMDSN = ISCSI_ERR_BASE + 3,
ISCSI_ERR_EXP_CMDSN = ISCSI_ERR_BASE + 4,
ISCSI_ERR_BAD_OPCODE = ISCSI_ERR_BASE + 5,
ISCSI_ERR_DATALEN = ISCSI_ERR_BASE + 6,
ISCSI_ERR_AHSLEN = ISCSI_ERR_BASE + 7,
ISCSI_ERR_PROTO = ISCSI_ERR_BASE + 8,
ISCSI_ERR_LUN = ISCSI_ERR_BASE + 9,
ISCSI_ERR_BAD_ITT = ISCSI_ERR_BASE + 10,
ISCSI_ERR_CONN_FAILED = ISCSI_ERR_BASE + 11,
ISCSI_ERR_R2TSN = ISCSI_ERR_BASE + 12,
ISCSI_ERR_SESSION_FAILED = ISCSI_ERR_BASE + 13,
ISCSI_ERR_HDR_DGST = ISCSI_ERR_BASE + 14,
ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15,
ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16,
ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17,
ISCSI_ERR_INVALID_HOST = ISCSI_ERR_BASE + 18,
ISCSI_ERR_XMIT_FAILED = ISCSI_ERR_BASE + 19,
ISCSI_ERR_TCP_CONN_CLOSE = ISCSI_ERR_BASE + 20,
ISCSI_ERR_SCSI_EH_SESSION_RST = ISCSI_ERR_BASE + 21,
ISCSI_ERR_NOP_TIMEDOUT = ISCSI_ERR_BASE + 22,
};
<snip>
enum iscsi_conn_state {
ISCSI_CONN_STATE_FREE, // 0
ISCSI_CONN_STATE_XPT_WAIT, // 1
ISCSI_CONN_STATE_IN_LOGIN, // 2
ISCSI_CONN_STATE_LOGGED_IN, // 3
ISCSI_CONN_STATE_IN_LOGOUT, // 4
ISCSI_CONN_STATE_LOGOUT_REQUESTED, // 5
ISCSI_CONN_STATE_CLEANUP_WAIT, // 6
};
<snip>
이후 커널에서도time out에 대한 메세지를 력 하였으며, 시간 및 경과 시간에 대해서 파악이 가능하다.
drivers/scsi/libiscsi.c
static void iscsi_check_transport_timeouts(unsigned long data)
{
<snip>
if (iscsi_has_ping_timed_out(conn)) {
iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
"expired, recv timeout %d, last rx %lu, "
"last ping %lu, now %lu\n",
conn->ping_timeout, conn->recv_timeout,
last_recv, conn->last_ping, jiffies);
spin_unlock(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_NOP_TIMEDOUT);
return;
}
if (time_before_eq(last_recv + recv_timeout, jiffies)) {
/* send a ping to try to provoke some traffic */
ISCSI_DBG_CONN(conn, "Sending nopout as ping\n");
if (iscsi_send_nopout(conn, NULL))
next_timeout = jiffies + (1 * HZ);
else
next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
} else
next_timeout = last_recv + recv_timeout;
<snip>