diff --git a/iscsi-scst/include/iscsi_scst.h b/iscsi-scst/include/iscsi_scst.h index be008e401..101c1e952 100644 --- a/iscsi-scst/include/iscsi_scst.h +++ b/iscsi-scst/include/iscsi_scst.h @@ -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) diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index 98dab88ee..9311a8b54 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -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); diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 15f617dc3..a32eeacc5 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -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 */ diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 00970cae8..798f824a9 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -33,10 +33,6 @@ #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); diff --git a/iscsi-scst/kernel/iscsi_hdr.h b/iscsi-scst/kernel/iscsi_hdr.h index d9378be20..3540403f5 100644 --- a/iscsi-scst/kernel/iscsi_hdr.h +++ b/iscsi-scst/kernel/iscsi_hdr.h @@ -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]) diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index a00d32248..5d619c88f 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -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)", diff --git a/iscsi-scst/kernel/param.c b/iscsi-scst/kernel/param.c index ce08437c5..9420f2570 100644 --- a/iscsi-scst/kernel/param.c +++ b/iscsi-scst/kernel/param.c @@ -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; } diff --git a/iscsi-scst/usr/event.c b/iscsi-scst/usr/event.c index 10dc3874c..7c83f3751 100644 --- a/iscsi-scst/usr/event.c +++ b/iscsi-scst/usr/event.c @@ -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(¶ms, 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); diff --git a/iscsi-scst/usr/iscsi_hdr.h b/iscsi-scst/usr/iscsi_hdr.h index fc77ffe28..ac2ff58c6 100644 --- a/iscsi-scst/usr/iscsi_hdr.h +++ b/iscsi-scst/usr/iscsi_hdr.h @@ -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 diff --git a/iscsi-scst/usr/param.c b/iscsi-scst/usr/param.c index 8f663a51d..5bb88d56d 100644 --- a/iscsi-scst/usr/param.c +++ b/iscsi-scst/usr/param.c @@ -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},