BUG_ON(value);
                session->ofmarker_en = value;
                break;
+       case ISCSI_PARAM_EXP_STATSN:
+               conn->exp_statsn = value;
+               break;
        default:
                break;
        }
                inet = inet_sk(tcp_conn->sock->sk);
                *value = be16_to_cpu(inet->dport);
                mutex_unlock(&conn->xmitmutex);
+       case ISCSI_PARAM_EXP_STATSN:
+               *value = conn->exp_statsn;
+               break;
        default:
                return -EINVAL;
        }
                                  ISCSI_DATASEQ_INORDER_EN |
                                  ISCSI_ERL |
                                  ISCSI_CONN_PORT |
-                                 ISCSI_CONN_ADDRESS,
+                                 ISCSI_CONN_ADDRESS |
+                                 ISCSI_EXP_STATSN,
        .host_template          = &iscsi_sht,
        .conndata_size          = sizeof(struct iscsi_conn),
        .max_conn               = 1,
 
                debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n",
                           opcode, conn->id, mtask->itt, datalen);
 
+               rc = iscsi_check_assign_cmdsn(session,
+                                             (struct iscsi_nopin*)hdr);
+               if (rc)
+                       goto done;
+
                switch(opcode) {
+               case ISCSI_OP_LOGOUT_RSP:
+                       conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+                       /* fall through */
                case ISCSI_OP_LOGIN_RSP:
                case ISCSI_OP_TEXT_RSP:
-               case ISCSI_OP_LOGOUT_RSP:
-                       rc = iscsi_check_assign_cmdsn(session,
-                                                (struct iscsi_nopin*)hdr);
-                       if (rc)
-                               break;
-
+                       /*
+                        * login related PDU's exp_statsn is handled in
+                        * userspace
+                        */
                        rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
                        list_del(&mtask->running);
                        if (conn->login_mtask != mtask)
                                            (void*)&mtask, sizeof(void*));
                        break;
                case ISCSI_OP_SCSI_TMFUNC_RSP:
-                       rc = iscsi_check_assign_cmdsn(session,
-                                                (struct iscsi_nopin*)hdr);
-                       if (rc)
-                               break;
-
                        if (datalen) {
                                rc = ISCSI_ERR_PROTO;
                                break;
                        }
+
+                       conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
                        conn->tmfrsp_pdus_cnt++;
                        if (conn->tmabort_state == TMABORT_INITIAL) {
                                conn->tmabort_state =
                                rc = ISCSI_ERR_PROTO;
                                break;
                        }
-                       rc = iscsi_check_assign_cmdsn(session,
-                                               (struct iscsi_nopin*)hdr);
-                       if (rc)
-                               break;
                        conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
 
                        rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
                case ISCSI_OP_REJECT:
                        /* we need sth like iscsi_reject_rsp()*/
                case ISCSI_OP_ASYNC_EVENT:
+                       conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
                        /* we need sth like iscsi_async_event_rsp() */
                        rc = ISCSI_ERR_BAD_OPCODE;
                        break;
        } else
                rc = ISCSI_ERR_BAD_ITT;
 
+done:
        return rc;
 }
 EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
                BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
                BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
+               nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
                if (!__kfifo_get(session->mgmtpool.queue,
                                 (void*)&mtask, sizeof(void*))) {
                        spin_unlock_bh(&session->lock);
        }
 
        /*
-        * pre-format CmdSN and ExpStatSN for outgoing PDU.
+        * pre-format CmdSN for outgoing PDU.
         */
        if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
                hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
                /* do not advance CmdSN */
                nop->cmdsn = cpu_to_be32(session->cmdsn);
 
-       nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
-
        if (data_size) {
                memcpy(mtask->data, data, data_size);
                mtask->data_count = data_size;
        case STOP_CONN_RECOVER:
        case STOP_CONN_TERM:
                iscsi_start_session_recovery(session, conn, flag);
-               return;
+               break;
        case STOP_CONN_SUSPEND:
                if (session->tt->suspend_conn_recv)
                        session->tt->suspend_conn_recv(conn);
 
 #include <scsi/iscsi_if.h>
 
 #define ISCSI_SESSION_ATTRS 11
-#define ISCSI_CONN_ATTRS 10
+#define ISCSI_CONN_ATTRS 11
 #define ISCSI_HOST_ATTRS 0
 
 struct iscsi_internal {
 iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
 iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d");
 iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d");
+iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u");
 
 #define iscsi_conn_str_attr_show(param)                                        \
 static ssize_t                                                         \
        SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);
        SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
        SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
+       SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
 
        if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS)
                SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);