Deeply reworked patch from Alexey Obitotskiy <alexeyo1@open-e.com> implementing suppo...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 5 Mar 2010 12:56:20 +0000 (12:56 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 5 Mar 2010 12:56:20 +0000 (12:56 +0000)
git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@1533 d57e44dd-8a1f-0410-8b47-8ef2f437770f

iscsi-scst/include/iscsi_scst.h
iscsi-scst/kernel/conn.c
iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/iscsi_hdr.h
iscsi-scst/kernel/nthread.c
iscsi-scst/kernel/param.c
iscsi-scst/usr/event.c
iscsi-scst/usr/iscsi_hdr.h
iscsi-scst/usr/param.c

index be008e4..101c1e9 100644 (file)
@@ -62,6 +62,8 @@ enum {
 
 enum {
        key_queued_cmnds,
+       key_rsp_timeout,
+       key_nop_in_interval,
        target_key_last,
 };
 
@@ -172,6 +174,14 @@ struct iscsi_kern_attr_info {
 #define        MIN_NR_QUEUED_CMNDS     1
 #define        MAX_NR_QUEUED_CMNDS     256
 
+#define DEFAULT_RSP_TIMEOUT    30
+#define MIN_RSP_TIMEOUT                10
+#define MAX_RSP_TIMEOUT                65535
+
+#define DEFAULT_NOP_IN_INTERVAL 30
+#define MIN_NOP_IN_INTERVAL    0
+#define MAX_NOP_IN_INTERVAL    65535
+
 #define NETLINK_ISCSI_SCST     25
 
 #define REGISTER_USERD         _IOWR('s', 0, struct iscsi_kern_register_info)
index 98dab88..9311a8b 100644 (file)
@@ -396,7 +396,6 @@ static void conn_rsp_timer_fn(unsigned long arg)
        struct iscsi_conn *conn = (struct iscsi_conn *)arg;
        struct iscsi_cmnd *cmnd;
        unsigned long j = jiffies;
-       unsigned long timeout_time = j + ISCSI_RSP_SCHED_TIMEOUT;
 
        TRACE_ENTRY();
 
@@ -405,11 +404,14 @@ static void conn_rsp_timer_fn(unsigned long arg)
        spin_lock_bh(&conn->write_list_lock);
 
        if (!list_empty(&conn->write_timeout_list)) {
+               unsigned long timeout_time;
                cmnd = list_entry(conn->write_timeout_list.next,
                                struct iscsi_cmnd, write_timeout_list_entry);
 
-               if (unlikely(time_after_eq(j,
-                               cmnd->write_start + ISCSI_RSP_TIMEOUT))) {
+               timeout_time = j + conn->rsp_timeout + ISCSI_ADD_SCHED_TIME;
+
+               if (unlikely(time_after_eq(j, cmnd->write_start +
+                                               conn->rsp_timeout))) {
                        if (!conn->closing) {
                                PRINT_ERROR("Timeout sending data/waiting "
                                        "for reply to/from initiator "
@@ -450,19 +452,50 @@ out:
        return;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void conn_nop_in_delayed_work_fn(void *p)
+#else
+static void conn_nop_in_delayed_work_fn(struct delayed_work *work)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+       struct iscsi_conn *conn = (struct iscsi_conn *)p;
+#else
+       struct iscsi_conn *conn = container_of(work, struct iscsi_conn,
+               nop_in_delayed_work);
+#endif
+
+       TRACE_ENTRY();
+
+       if (time_after_eq(jiffies, conn->last_rcv_time +
+                               conn->nop_in_interval)) {
+               iscsi_send_nop_in(conn);
+       }
+
+       if (conn->nop_in_interval > 0) {
+               TRACE_DBG("Reschedule NOP-In work for conn %p", conn);
+               schedule_delayed_work(&conn->nop_in_delayed_work,
+                       conn->nop_in_interval + ISCSI_ADD_SCHED_TIME);
+       }
+
+       TRACE_EXIT();
+       return;
+}
+
 /* Must be called from rd thread only */
 void iscsi_check_tm_data_wait_timeouts(struct iscsi_conn *conn, bool force)
 {
        struct iscsi_cmnd *cmnd;
        unsigned long j = jiffies;
        bool aborted_cmds_pending;
-       unsigned long timeout_time = j + ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT;
+       unsigned long timeout_time = j + ISCSI_TM_DATA_WAIT_TIMEOUT +
+                                       ISCSI_ADD_SCHED_TIME;
 
        TRACE_ENTRY();
 
        TRACE_DBG_FLAG(force ? TRACE_CONN_OC_DBG : TRACE_MGMT_DEBUG,
                "j %ld (TIMEOUT %d, force %d)", j,
-               ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT, force);
+               ISCSI_TM_DATA_WAIT_TIMEOUT + ISCSI_ADD_SCHED_TIME, force);
 
        iscsi_extracheck_is_rd_thread(conn);
 
@@ -707,6 +740,25 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
        init_waitqueue_head(&conn->read_state_waitQ);
        init_completion(&conn->ready_to_free);
        INIT_LIST_HEAD(&conn->reinst_pending_cmd_list);
+       INIT_LIST_HEAD(&conn->nop_req_list);
+       spin_lock_init(&conn->nop_req_list_lock);
+
+       conn->nop_in_ttt = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
+       INIT_DELAYED_WORK(&conn->nop_in_delayed_work,
+               (void (*)(struct work_struct *))conn_nop_in_delayed_work_fn);
+#else
+       INIT_WORK(&conn->nop_in_delayed_work, conn_nop_in_delayed_work_fn,
+               conn);
+#endif
+       conn->last_rcv_time = jiffies;
+       conn->rsp_timeout = session->tgt_params.rsp_timeout * HZ;
+       conn->nop_in_interval = session->tgt_params.nop_in_interval * HZ;
+       if (conn->nop_in_interval > 0) {
+               TRACE_DBG("Schedule NOP-In work for conn %p", conn);
+               schedule_delayed_work(&conn->nop_in_delayed_work,
+                       conn->nop_in_interval + ISCSI_ADD_SCHED_TIME);
+       }
 
        conn->file = fget(info->fd);
 
index 15f617d..a32eeac 100644 (file)
@@ -1546,7 +1546,7 @@ out:
        return res;
 }
 
-static int noop_out_start(struct iscsi_cmnd *cmnd)
+static int nop_out_start(struct iscsi_cmnd *cmnd)
 {
        struct iscsi_conn *conn = cmnd->conn;
        struct iscsi_hdr *req_hdr = &cmnd->pdu.bhs;
@@ -2053,7 +2053,8 @@ out:
 /* Might be called under target_mutex and cmd_list_lock */
 static void __cmnd_abort(struct iscsi_cmnd *cmnd)
 {
-       unsigned long timeout_time = jiffies + ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT;
+       unsigned long timeout_time = jiffies + ISCSI_TM_DATA_WAIT_TIMEOUT +
+                                       ISCSI_ADD_SCHED_TIME;
        struct iscsi_conn *conn = cmnd->conn;
 
        TRACE_MGMT_DBG("Aborting cmd %p, scst_cmd %p (scst state %x, "
@@ -2284,12 +2285,21 @@ static void task_set_abort(struct iscsi_cmnd *req)
 /* Must be called from the read or conn close thread */
 void conn_abort(struct iscsi_conn *conn)
 {
-       struct iscsi_cmnd *cmnd;
+       struct iscsi_cmnd *cmnd, *r, *t;
 
        TRACE_MGMT_DBG("Aborting conn %p", conn);
 
        iscsi_extracheck_is_rd_thread(conn);
 
+       cancel_delayed_work_sync(&conn->nop_in_delayed_work);
+
+       /* No locks, we are the only user */
+       list_for_each_entry_safe(r, t, &conn->nop_req_list,
+                       nop_req_list_entry) {
+               list_del(&r->nop_req_list_entry);
+               cmnd_put(r);
+       }
+
        spin_lock_bh(&conn->cmd_list_lock);
 again:
        list_for_each_entry(cmnd, &conn->cmd_list, cmd_list_entry) {
@@ -2461,7 +2471,7 @@ reject:
        return;
 }
 
-static void noop_out_exec(struct iscsi_cmnd *req)
+static void nop_out_exec(struct iscsi_cmnd *req)
 {
        struct iscsi_cmnd *rsp;
        struct iscsi_nop_in_hdr *rsp_hdr;
@@ -2474,7 +2484,7 @@ static void noop_out_exec(struct iscsi_cmnd *req)
                rsp = iscsi_alloc_main_rsp(req);
 
                rsp_hdr = (struct iscsi_nop_in_hdr *)&rsp->pdu.bhs;
-               rsp_hdr->opcode = ISCSI_OP_NOOP_IN;
+               rsp_hdr->opcode = ISCSI_OP_NOP_IN;
                rsp_hdr->flags = ISCSI_FLG_FINAL;
                rsp_hdr->itt = req->pdu.bhs.itt;
                rsp_hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
@@ -2494,6 +2504,30 @@ static void noop_out_exec(struct iscsi_cmnd *req)
                sBUG_ON(get_pgcnt(req->pdu.datasize, 0) > ISCSI_CONN_IOV_MAX);
 
                rsp->pdu.datasize = req->pdu.datasize;
+       } else {
+               bool found = false;
+               struct iscsi_cmnd *r;
+               struct iscsi_conn *conn = req->conn;
+
+               TRACE_DBG("Receive NOP-in response (ttt 0x%08x)",
+                       be32_to_cpu(cmnd_ttt(req)));
+
+               spin_lock_bh(&conn->nop_req_list_lock);
+               list_for_each_entry(r, &conn->nop_req_list,
+                               nop_req_list_entry) {
+                       if (cmnd_ttt(req) == cmnd_ttt(r)) {
+                               list_del(&r->nop_req_list_entry);
+                               found = true;
+                               break;
+                       }
+               }
+               spin_unlock_bh(&conn->nop_req_list_lock);
+
+               if (found)
+                       cmnd_put(r);
+               else
+                       TRACE_MGMT_DBG("%s", "Got NOP-out response without "
+                               "corresponding NOP-in request");
        }
 
        req_cmnd_release(req);
@@ -2550,8 +2584,8 @@ static void iscsi_cmnd_exec(struct iscsi_cmnd *cmnd)
        }
 
        switch (cmnd_opcode(cmnd)) {
-       case ISCSI_OP_NOOP_OUT:
-               noop_out_exec(cmnd);
+       case ISCSI_OP_NOP_OUT:
+               nop_out_exec(cmnd);
                break;
        case ISCSI_OP_SCSI_TASK_MGT_MSG:
                execute_task_management(cmnd);
@@ -2602,8 +2636,11 @@ void cmnd_tx_start(struct iscsi_cmnd *cmnd)
        conn->write_offset = 0;
 
        switch (cmnd_opcode(cmnd)) {
-       case ISCSI_OP_NOOP_IN:
-               cmnd_set_sn(cmnd, 1);
+       case ISCSI_OP_NOP_IN:
+               if (cmnd_itt(cmnd) == cpu_to_be32(ISCSI_RESERVED_TAG))
+                       cmnd->pdu.bhs.sn = cmnd_set_sn(cmnd, 0);
+               else
+                       cmnd_set_sn(cmnd, 1);
                break;
        case ISCSI_OP_SCSI_RSP:
                cmnd_set_sn(cmnd, 1);
@@ -2662,7 +2699,7 @@ void cmnd_tx_end(struct iscsi_cmnd *cmnd)
 
 #ifdef CONFIG_SCST_EXTRACHECKS
        switch (cmnd_opcode(cmnd)) {
-       case ISCSI_OP_NOOP_IN:
+       case ISCSI_OP_NOP_IN:
        case ISCSI_OP_SCSI_RSP:
        case ISCSI_OP_SCSI_TASK_MGT_RSP:
        case ISCSI_OP_TEXT_RSP:
@@ -2892,8 +2929,8 @@ int cmnd_rx_start(struct iscsi_cmnd *cmnd)
        case ISCSI_OP_SCSI_DATA_OUT:
                res = data_out_start(cmnd);
                goto out;
-       case ISCSI_OP_NOOP_OUT:
-               rc = noop_out_start(cmnd);
+       case ISCSI_OP_NOP_OUT:
+               rc = nop_out_start(cmnd);
                break;
        case ISCSI_OP_SCSI_TASK_MGT_MSG:
        case ISCSI_OP_LOGOUT_CMD:
@@ -2926,9 +2963,12 @@ void cmnd_rx_end(struct iscsi_cmnd *cmnd)
 
        TRACE_DBG("cmnd %p, opcode %x", cmnd, cmnd_opcode(cmnd));
 
+       cmnd->conn->last_rcv_time = jiffies;
+       TRACE_DBG("Updated last_rcv_time %ld", cmnd->conn->last_rcv_time);
+
        switch (cmnd_opcode(cmnd)) {
        case ISCSI_OP_SCSI_CMD:
-       case ISCSI_OP_NOOP_OUT:
+       case ISCSI_OP_NOP_OUT:
        case ISCSI_OP_SCSI_TASK_MGT_MSG:
        case ISCSI_OP_LOGOUT_CMD:
                iscsi_push_cmnd(cmnd);
@@ -3440,6 +3480,51 @@ static int iscsi_report_aen(struct scst_aen *aen)
        return res;
 }
 
+void iscsi_send_nop_in(struct iscsi_conn *conn)
+{
+       struct iscsi_cmnd *req, *rsp;
+       struct iscsi_nop_in_hdr *rsp_hdr;
+
+       TRACE_ENTRY();
+
+       req = cmnd_alloc(conn, NULL);
+       if (req == NULL) {
+               PRINT_ERROR("%s", "Unable to alloc fake NOP-IN request");
+               goto out_err;
+       }
+
+       rsp = iscsi_alloc_main_rsp(req);
+       if (rsp == NULL) {
+               PRINT_ERROR("%s", "Unable to alloc NOP-IN rsp");
+               goto out_err_free_req;
+       }
+
+       cmnd_get(rsp);
+
+       rsp_hdr = (struct iscsi_nop_in_hdr *)&rsp->pdu.bhs;
+       rsp_hdr->opcode = ISCSI_OP_NOP_IN;
+       rsp_hdr->flags = ISCSI_FLG_FINAL;
+       rsp_hdr->itt = cpu_to_be32(ISCSI_RESERVED_TAG);
+       rsp_hdr->ttt = conn->nop_in_ttt++;
+
+       if (conn->nop_in_ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
+               conn->nop_in_ttt = 0;
+
+       /* Supposed that all other fields are zeroed */
+
+       TRACE_DBG("Sending NOP-in request (ttt 0x%08x)", rsp_hdr->ttt);
+       spin_lock_bh(&conn->nop_req_list_lock);
+       list_add_tail(&rsp->nop_req_list_entry, &conn->nop_req_list);
+       spin_unlock_bh(&conn->nop_req_list_lock);
+
+out_err_free_req:
+       req_cmnd_release(req);
+
+out_err:
+       TRACE_EXIT();
+       return;
+}
+
 static int iscsi_target_detect(struct scst_tgt_template *templ)
 {
        /* Nothing to do */
index 00970ca..798f824 100644 (file)
 #define iscsi_sense_unexpected_unsolicited_data        ABORTED_COMMAND, 0x0C, 0x0C
 #define iscsi_sense_incorrect_amount_of_data   ABORTED_COMMAND, 0x0C, 0x0D
 
-/*
- * All members must have int type to match expectations of iscsi_tgt_store_*()
- * functions!
- */
 struct iscsi_sess_params {
        int initial_r2t;
        int immediate_data;
@@ -59,12 +55,10 @@ struct iscsi_sess_params {
        int ifmarkint;
 };
 
-/*
- * All members must have int type to match expectations of iscsi_tgt_store_*()
- * functions!
- */
 struct iscsi_tgt_params {
        int queued_cmnds;
+       unsigned int rsp_timeout;
+       unsigned int nop_in_interval;
 };
 
 struct network_thread_info {
@@ -191,6 +185,7 @@ struct iscsi_conn {
 
        /* Protected by write_list_lock */
        struct timer_list rsp_timer;
+       unsigned int rsp_timeout; /* in jiffies */
 
        /* All 2 protected by iscsi_wr_lock */
        unsigned short wr_state;
@@ -241,6 +236,8 @@ struct iscsi_conn {
        struct task_struct *rd_task;
 #endif
 
+       unsigned long last_rcv_time;
+
        /*
         * All are unprotected, since accessed only from a single read
         * thread.
@@ -267,6 +264,16 @@ struct iscsi_conn {
        /* Doesn't need any protection */
        u16 cid;
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
+       struct delayed_work nop_in_delayed_work;
+#else
+       struct work_struct nop_in_delayed_work;
+#endif
+       unsigned int nop_in_interval; /* in jiffies */
+       struct list_head nop_req_list;
+       spinlock_t nop_req_list_lock;
+       u32 nop_in_ttt;
+
 #ifndef CONFIG_SCST_PROC
        /* Doesn't need any protection */
        struct kobject iscsi_conn_kobj;
@@ -436,21 +443,17 @@ struct iscsi_cmnd {
        u32 ddigest;
 
        struct list_head cmd_list_entry;
+       struct list_head nop_req_list_entry;
 };
 
-/**
- ** Various timeouts. *_SCHED_TIMEOUT is needed to complete a burst of
- ** commands at once. Otherwise, a part of the burst can be timeouted
- ** only in double timeout time.
- **/
-
-/* Max time to wait for our response satisfied */
-#define ISCSI_RSP_TIMEOUT              (30 * HZ)
-#define ISCSI_RSP_SCHED_TIMEOUT                (ISCSI_RSP_TIMEOUT + HZ)
-
 /* Max time to wait for our response satisfied for aborted commands */
 #define ISCSI_TM_DATA_WAIT_TIMEOUT     (10 * HZ)
-#define ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT (ISCSI_TM_DATA_WAIT_TIMEOUT + HZ)
+
+/*
+ * Needed addition to all timeouts to complete a burst of commands at once.
+ * Otherwise, a part of the burst can be timeouted only in double timeout time.
+ */
+#define ISCSI_ADD_SCHED_TIME           HZ
 
 #define ISCSI_CTR_OPEN_STATE_CLOSED    0
 #define ISCSI_CTR_OPEN_STATE_OPEN      1
@@ -483,6 +486,7 @@ extern void cmnd_done(struct iscsi_cmnd *cmnd);
 extern void conn_abort(struct iscsi_conn *conn);
 extern void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd);
 extern void iscsi_fail_data_waiting_cmnd(struct iscsi_cmnd *cmnd);
+extern void iscsi_send_nop_in(struct iscsi_conn *conn);
 
 /* conn.c */
 extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
index d9378be..3540403 100644 (file)
@@ -53,7 +53,7 @@ struct iscsi_hdr {
 #define ISCSI_OPCODE_MASK              0x3F
 
 /* Client to Server Message Opcode values */
-#define ISCSI_OP_NOOP_OUT              0x00
+#define ISCSI_OP_NOP_OUT               0x00
 #define ISCSI_OP_SCSI_CMD              0x01
 #define ISCSI_OP_SCSI_TASK_MGT_MSG     0x02
 #define ISCSI_OP_LOGIN_CMD             0x03
@@ -63,7 +63,7 @@ struct iscsi_hdr {
 #define ISCSI_OP_SNACK_CMD             0x10
 
 /* Server to Client Message Opcode values */
-#define ISCSI_OP_NOOP_IN               0x20
+#define ISCSI_OP_NOP_IN                        0x20
 #define ISCSI_OP_SCSI_RSP              0x21
 #define ISCSI_OP_SCSI_TASK_MGT_RSP     0x22
 #define ISCSI_OP_LOGIN_RSP             0x23
@@ -512,6 +512,7 @@ struct iscsi_nop_in_hdr {
 
 #define cmnd_hdr(cmnd) ((struct iscsi_scsi_cmd_hdr *) (&((cmnd)->pdu.bhs)))
 #define cmnd_itt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.itt)
+#define cmnd_ttt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.ttt)
 #define cmnd_opcode(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OPCODE_MASK)
 #define cmnd_scsicode(cmnd) (cmnd_hdr((cmnd))->scb[0])
 
index a00d322..5d619c8 100644 (file)
@@ -1173,10 +1173,11 @@ void req_add_to_write_timeout_list(struct iscsi_cmnd *req)
                                        &req->prelim_compl_flags))) {
                        set_conn_tm_active = true;
                        timeout_time = req->write_start +
-                               ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT;
+                                       ISCSI_TM_DATA_WAIT_TIMEOUT +
+                                       ISCSI_ADD_SCHED_TIME;
                } else
                        timeout_time = req->write_start +
-                               ISCSI_RSP_SCHED_TIMEOUT;
+                               conn->rsp_timeout + ISCSI_ADD_SCHED_TIME;
 
                TRACE_DBG("Starting timer on %ld (con %p, write_start %ld)",
                        timeout_time, conn, req->write_start);
@@ -1186,7 +1187,7 @@ void req_add_to_write_timeout_list(struct iscsi_cmnd *req)
        } else if (unlikely(test_bit(ISCSI_CMD_ABORTED,
                                &req->prelim_compl_flags))) {
                unsigned long timeout_time = jiffies +
-                                       ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT;
+                       ISCSI_TM_DATA_WAIT_TIMEOUT + ISCSI_ADD_SCHED_TIME;
                set_conn_tm_active = true;
                if (time_after(conn->rsp_timer.expires, timeout_time)) {
                        TRACE_MGMT_DBG("Mod timer on %ld (conn %p)",
index ce08437..9420f25 100644 (file)
@@ -39,7 +39,7 @@ do {                                                                          \
                if ((params)->word != (iparams)[key_##word])                    \
                        changed = 1;                                            \
                (params)->word = (iparams)[key_##word];                         \
-               TRACE_DBG("%s set to %u", #word, (iparams)[key_##word]);        \
+               TRACE_DBG("%s set to %u", #word, (params)->word);               \
        }                                                                       \
        changed;                                                                \
 })
@@ -192,26 +192,10 @@ static void tgt_params_check(struct iscsi_kern_params_info *info)
 
        CHECK_PARAM(info, iparams, queued_cmnds, MIN_NR_QUEUED_CMNDS,
                    MAX_NR_QUEUED_CMNDS);
-       return;
-}
-
-/* target_mutex supposed to be locked */
-static void tgt_params_set(struct iscsi_tgt_params *params,
-                          struct iscsi_kern_params_info *info)
-{
-       int32_t *iparams = info->target_params;
-
-       SET_PARAM(params, info, iparams, queued_cmnds);
-       return;
-}
-
-/* target_mutex supposed to be locked */
-static void tgt_params_get(struct iscsi_tgt_params *params,
-                          struct iscsi_kern_params_info *info)
-{
-       int32_t *iparams = info->target_params;
-
-       GET_PARAM(params, info, iparams, queued_cmnds);
+       CHECK_PARAM(info, iparams, rsp_timeout, MIN_RSP_TIMEOUT,
+               MAX_RSP_TIMEOUT);
+       CHECK_PARAM(info, iparams, nop_in_interval, MIN_NOP_IN_INTERVAL,
+               MAX_NOP_IN_INTERVAL);
        return;
 }
 
@@ -220,15 +204,39 @@ static int iscsi_tgt_params_set(struct iscsi_session *session,
                      struct iscsi_kern_params_info *info, int set)
 {
        struct iscsi_tgt_params *params = &session->tgt_params;
+       int32_t *iparams = info->target_params;
 
        if (set) {
+               struct iscsi_conn *conn;
+
                tgt_params_check(info);
-               tgt_params_set(params, info);
+
+               SET_PARAM(params, info, iparams, queued_cmnds);
+               SET_PARAM(params, info, iparams, rsp_timeout);
+               SET_PARAM(params, info, iparams, nop_in_interval);
+
                PRINT_INFO("Target parameters set for session %llx: "
-                       "QueuedCommands %d", session->sid,
-                       params->queued_cmnds);
-       } else
-               tgt_params_get(params, info);
+                       "QueuedCommands %d, Response timeout %d, NOP-in "
+                       "interval %d", session->sid, params->queued_cmnds,
+                       params->rsp_timeout, params->nop_in_interval);
+
+               list_for_each_entry(conn, &session->conn_list,
+                                       conn_list_entry) {
+                       conn->rsp_timeout = session->tgt_params.rsp_timeout * HZ;
+                       conn->nop_in_interval = session->tgt_params.nop_in_interval * HZ;
+                       spin_lock_bh(&iscsi_rd_lock);
+                       if (!conn->closing && (conn->nop_in_interval > 0)) {
+                               TRACE_DBG("Schedule NOP-In work for conn %p", conn);
+                               schedule_delayed_work(&conn->nop_in_delayed_work,
+                                       conn->nop_in_interval + ISCSI_ADD_SCHED_TIME);
+                       }
+                       spin_unlock_bh(&iscsi_rd_lock);
+               }
+       } else {
+               GET_PARAM(params, info, iparams, queued_cmnds);
+               GET_PARAM(params, info, iparams, rsp_timeout);
+               GET_PARAM(params, info, iparams, nop_in_interval);
+       }
 
        return 0;
 }
@@ -273,7 +281,8 @@ int iscsi_params_set(struct iscsi_target *target,
                goto out;
        }
 
-       if (set && !list_empty(&session->conn_list)) {
+       if (set && !list_empty(&session->conn_list) &&
+           (info->params_type != key_target)) {
                err = -EBUSY;
                goto out;
        }
index 10dc387..7c83f37 100644 (file)
@@ -538,6 +538,9 @@ static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
        p = buf;
        pp = config_sep_string(&p);
        if (!((idx = params_index_by_name(pp, target_keys)) < 0)) {
+               struct iscsi_param params[target_key_last];
+               struct session *session;
+
                if (target == NULL) {
                        log_error("Target expected for attr %s", pp);
                        res = -EINVAL;
@@ -568,6 +571,13 @@ static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
                }
 
                target->target_params[idx] = val;
+
+               memset(&params, 0, sizeof(params));
+               params[idx].val = val;
+               list_for_each_entry(session, &target->sessions_list, slist) {
+                       kernel_params_set(event->tid, session->sid.id64,
+                               key_target, 1 << idx, params);
+               }
        } else if (!((idx = params_index_by_name(pp, session_keys)) < 0)) {
                if (target == NULL) {
                        log_error("Target expected for attr %s", pp);
index fc77ffe..ac2ff58 100644 (file)
@@ -42,7 +42,7 @@ struct iscsi_hdr {
 #define ISCSI_OPCODE_MASK              0x3F
 
 /* Client to Server Message Opcode values */
-#define ISCSI_OP_NOOP_OUT              0x00
+#define ISCSI_OP_NOP_OUT               0x00
 #define ISCSI_OP_SCSI_CMD              0x01
 #define ISCSI_OP_SCSI_TASK_MGT_MSG     0x02
 #define ISCSI_OP_LOGIN_CMD             0x03
@@ -52,7 +52,7 @@ struct iscsi_hdr {
 #define ISCSI_OP_SNACK_CMD             0x10
 
 /* Server to Client Message Opcode values */
-#define ISCSI_OP_NOOP_IN               0x20
+#define ISCSI_OP_NOP_IN                        0x20
 #define ISCSI_OP_SCSI_RSP              0x21
 #define ISCSI_OP_SCSI_TASK_MGT_RSP     0x22
 #define ISCSI_OP_LOGIN_RSP             0x23
index 8f663a5..5bb88d5 100644 (file)
@@ -61,7 +61,6 @@ int params_index_by_name_numwild(char *name, struct iscsi_key *keys)
                        for (j = strlen(keys[i].name); j < strlen(name); j++) {
                                if (!isdigit(name[j]))
                                        goto next;
-                               
                        }
                        err = i;
                        break;
@@ -336,7 +335,7 @@ static struct iscsi_key_ops marker_ops = {
        .set_val = marker_set_val,
 };
 
-#define        SET_KEY_VALUES(x)       DEFAULT_NR_##x,DEFAULT_NR_##x,MIN_NR_##x,MAX_NR_##x
+#define        SET_KEY_VALUES(x)       DEFAULT_##x,DEFAULT_##x,MIN_##x,MAX_##x
 
 /*
  * List of local target keys with initial values.
@@ -346,7 +345,10 @@ static struct iscsi_key_ops marker_ops = {
  * the kernel as well!
  */
 struct iscsi_key target_keys[] = {
-       {"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), 1, &minimum_ops},
+       /* name,  rfc_def, local_def, min, max, show_in_sysfs, ops */
+       {"QueuedCommands", SET_KEY_VALUES(NR_QUEUED_CMNDS), 1, &minimum_ops},
+       {"RspTimeout", SET_KEY_VALUES(RSP_TIMEOUT), 1, &minimum_ops},
+       {"NoopInInterval", SET_KEY_VALUES(NOP_IN_INTERVAL), 1, &minimum_ops},
        {NULL,},
 };
 
@@ -358,6 +360,7 @@ struct iscsi_key target_keys[] = {
  * the kernel as well!
  */
 struct iscsi_key session_keys[] = {
+       /* name,  rfc_def, local_def, min, max, show_in_sysfs, ops */
        {"InitialR2T", 1, 0, 0, 1, 1, &or_ops},
        {"ImmediateData", 1, 1, 0, 1, 1, &and_ops},
        {"MaxConnections", 1, 1, 1, 1, 0, &minimum_ops},