mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-17 20:56:24 +00:00
- Update to the latest IET r145
- TM fixes and improvements, particularly, TARGET RESET now resets only visible to the initiator devices - Logs improvements git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@237 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+21
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
USER SPACE INTERFACE DESCRIPTION.
|
||||
|
||||
Version 0.9.6/2
|
||||
Version 0.9.6/3
|
||||
|
||||
|
||||
I. Description.
|
||||
@@ -335,6 +335,8 @@ struct scst_user_scsi_cmd_parse
|
||||
uint8_t expected_values_set;
|
||||
uint8_t expected_data_direction;
|
||||
int32_t expected_transfer_len;
|
||||
|
||||
uint32_t sn;
|
||||
},
|
||||
|
||||
where:
|
||||
@@ -362,6 +364,8 @@ where:
|
||||
|
||||
- expected_transfer_len - remote initiator supplied transfer length
|
||||
|
||||
- sn - command's SN, which might be used for task management
|
||||
|
||||
In the PARSE state of SCSI commands processing the user space device
|
||||
handler shall check and provide SCST values for command data buffer
|
||||
length, data flow direction and timeout, which it shall reply using the
|
||||
@@ -401,6 +405,8 @@ struct scst_user_scsi_cmd_alloc_mem
|
||||
|
||||
uint8_t queue_type;
|
||||
uint8_t data_direction;
|
||||
|
||||
uint32_t sn;
|
||||
},
|
||||
|
||||
where:
|
||||
@@ -418,6 +424,8 @@ where:
|
||||
- data_direction - command's data flow direction, one of SCST_DATA_*
|
||||
constants
|
||||
|
||||
- sn - command's SN, which might be used for task management
|
||||
|
||||
Memory allocation, preparation and freeing are ones of the most
|
||||
complicated and expensive operations during SCSI commands processing.
|
||||
Module scst_user provides a way to almost completely eliminate those
|
||||
@@ -507,6 +515,8 @@ struct scst_user_scsi_cmd_exec
|
||||
uint8_t partial;
|
||||
uint32_t timeout;
|
||||
|
||||
uint32_t sn;
|
||||
|
||||
uint32_t parent_cmd_h;
|
||||
int32_t parent_cmd_data_len;
|
||||
uint32_t partial_offset;
|
||||
@@ -546,6 +556,8 @@ where:
|
||||
|
||||
- timeout - CDB execution timeout
|
||||
|
||||
- sn - command's SN, which might be used for task management
|
||||
|
||||
- parent_cmd_h - has the same unique value for all partial data
|
||||
transfers subcommands of one original (parent) command
|
||||
|
||||
@@ -641,6 +653,8 @@ struct scst_user_tm
|
||||
uint64_t sess_h;
|
||||
uint32_t fn;
|
||||
uint32_t cmd_h_to_abort;
|
||||
uint32_t cmd_sn;
|
||||
uint8_t cmd_sn_set;
|
||||
},
|
||||
|
||||
where:
|
||||
@@ -651,6 +665,12 @@ where:
|
||||
|
||||
- cmd_h_to_abort - handle of command to abort. Valid only if fn is
|
||||
SCST_ABORT_TASK
|
||||
|
||||
- cmd_sn - if cmd_sn_set is set, contains maximum commands SN, which
|
||||
this task management function affects. See iSCSI RFC 3720 10.5.1 for
|
||||
more details.
|
||||
|
||||
- cmd_sn_set - specifies if cmd_sn is valid
|
||||
|
||||
After TM function is completed, the user space device handler shall
|
||||
reply using "result" field of the corresponding reply command. It isn't
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#define ISCSI_VERSION_STRING "0.9.6/0.4.15r137"
|
||||
#define ISCSI_VERSION_STRING "0.9.6/0.4.15r145"
|
||||
|
||||
/* The maximum length of 223 bytes in the RFC. */
|
||||
#define ISCSI_NAME_LEN 256
|
||||
|
||||
+110
-53
@@ -62,7 +62,7 @@ static LIST_HEAD(iscsi_threads_list);
|
||||
static void cmnd_remove_hash(struct iscsi_cmnd *cmnd);
|
||||
static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status);
|
||||
static void cmnd_prepare_skip_pdu(struct iscsi_cmnd *cmnd);
|
||||
static void iscsi_cond_send_tm_resp(struct iscsi_cmnd *rsp, int force);
|
||||
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess);
|
||||
|
||||
static inline u32 cmnd_write_size(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
@@ -780,8 +780,10 @@ static int cmnd_insert_hash(struct iscsi_cmnd *cmnd)
|
||||
if (!tmp) {
|
||||
list_add_tail(&cmnd->hash_list_entry, head);
|
||||
cmnd->hashed = 1;
|
||||
} else
|
||||
} else {
|
||||
PRINT_ERROR("Task %x in progress, cmnd %p", itt, cmnd);
|
||||
err = -ISCSI_REASON_TASK_IN_PROGRESS;
|
||||
}
|
||||
|
||||
spin_unlock(&session->cmnd_hash_lock);
|
||||
|
||||
@@ -965,6 +967,13 @@ static void send_r2t(struct iscsi_cmnd *req)
|
||||
u32 length, offset, burst;
|
||||
LIST_HEAD(send);
|
||||
|
||||
if (unlikely(req->tmfabort)) {
|
||||
TRACE_MGMT_DBG("req %p (scst_cmd %p) aborted on R2T", req,
|
||||
req->scst_cmd);
|
||||
req_cmnd_release_force(req, ISCSI_FORCE_RELEASE_WRITE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no race with data_out_start() and __cmnd_abort(), since
|
||||
* all functions called from single read thread
|
||||
@@ -1009,6 +1018,9 @@ static void send_r2t(struct iscsi_cmnd *req)
|
||||
iscsi_cmnds_init_write(&send, ISCSI_INIT_WRITE_WAKE);
|
||||
|
||||
req->data_waiting = 1;
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static int iscsi_pre_exec(struct scst_cmd *scst_cmd)
|
||||
@@ -1333,7 +1345,8 @@ static int data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
|
||||
cmnd->cmd_req = req = cmnd_find_hash(conn->session, req_hdr->itt,
|
||||
req_hdr->ttt);
|
||||
if (!req) {
|
||||
PRINT_ERROR("Unable to find scsi task %x %x",
|
||||
/* It might happen if req was aborted and then freed */
|
||||
TRACE(TRACE_MGMT_MINOR, "Unable to find scsi task %x %x",
|
||||
cmnd_itt(cmnd), cmnd_ttt(cmnd));
|
||||
goto skip_pdu;
|
||||
}
|
||||
@@ -1447,12 +1460,12 @@ static inline int __cmnd_abort(struct iscsi_cmnd *cmnd)
|
||||
goto out;
|
||||
|
||||
TRACE_MGMT_DBG("Aborting cmd %p, scst_cmd %p (scst state %x, "
|
||||
"ref_cnt %d, itt %x, op %x, r2t_len %x, CDB op %x, "
|
||||
"ref_cnt %d, itt %x, sn %d, op %x, r2t_len %x, CDB op %x, "
|
||||
"size to write %u, is_unsolicited_data %u, "
|
||||
"outstanding_r2t %u)", cmnd, cmnd->scst_cmd,
|
||||
cmnd->scst_state, atomic_read(&cmnd->ref_cnt),
|
||||
cmnd_itt(cmnd), cmnd_opcode(cmnd), cmnd->r2t_length,
|
||||
cmnd_scsicode(cmnd), cmnd_write_size(cmnd),
|
||||
cmnd_itt(cmnd), cmnd->pdu.bhs.sn, cmnd_opcode(cmnd),
|
||||
cmnd->r2t_length, cmnd_scsicode(cmnd), cmnd_write_size(cmnd),
|
||||
cmnd->is_unsolicited_data, cmnd->outstanding_r2t);
|
||||
|
||||
#ifdef NET_PAGE_CALLBACKS_DEFINED
|
||||
@@ -1615,26 +1628,32 @@ again:
|
||||
static void execute_task_management(struct iscsi_cmnd *req)
|
||||
{
|
||||
struct iscsi_conn *conn = req->conn;
|
||||
struct iscsi_session *sess = conn->session;
|
||||
struct iscsi_task_mgt_hdr *req_hdr =
|
||||
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
|
||||
int err = 0, function = req_hdr->function & ISCSI_FUNCTION_MASK;
|
||||
struct scst_rx_mgmt_params params;
|
||||
|
||||
TRACE((function == ISCSI_FUNCTION_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
|
||||
"TM cmd: req %p, itt %x, fn %d, rtt %x", req, cmnd_itt(req),
|
||||
function, req_hdr->rtt);
|
||||
"TM cmd: req %p, itt %x, fn %d, rtt %x, sn %d", req, cmnd_itt(req),
|
||||
function, req_hdr->rtt, req_hdr->cmd_sn);
|
||||
|
||||
spin_lock(&sess->sn_lock);
|
||||
sess->tm_active = 1;
|
||||
sess->tm_sn = req_hdr->cmd_sn;
|
||||
if (sess->tm_rsp != NULL) {
|
||||
struct iscsi_cmnd *tm_rsp = sess->tm_rsp;
|
||||
TRACE(TRACE_MGMT_MINOR, "Dropping delayed TM rsp %p", tm_rsp);
|
||||
sess->tm_rsp = NULL;
|
||||
spin_unlock(&sess->sn_lock);
|
||||
rsp_cmnd_release(tm_rsp);
|
||||
} else
|
||||
spin_unlock(&sess->sn_lock);
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.atomic = SCST_NON_ATOMIC;
|
||||
params.tgt_priv = req;
|
||||
|
||||
if (conn->session->tm_rsp != NULL) {
|
||||
struct iscsi_task_rsp_hdr *rsp_hdr =
|
||||
(struct iscsi_task_rsp_hdr *)&conn->session->tm_rsp->pdu.bhs;
|
||||
rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_REJECTED;
|
||||
iscsi_cond_send_tm_resp(conn->session->tm_rsp, 1);
|
||||
}
|
||||
|
||||
if ((function != ISCSI_FUNCTION_ABORT_TASK) &&
|
||||
(req_hdr->rtt != ISCSI_RESERVED_TAG)) {
|
||||
PRINT_ERROR("Invalid RTT %x (TM fn %x)", req_hdr->rtt,
|
||||
@@ -1697,6 +1716,8 @@ static void execute_task_management(struct iscsi_cmnd *req)
|
||||
case ISCSI_FUNCTION_TARGET_WARM_RESET:
|
||||
target_abort(req, 1);
|
||||
params.fn = SCST_TARGET_RESET;
|
||||
params.cmd_sn = req_hdr->cmd_sn;
|
||||
params.cmd_sn_set = 1;
|
||||
err = scst_rx_mgmt_fn(conn->session->scst_sess,
|
||||
¶ms);
|
||||
break;
|
||||
@@ -1706,6 +1727,8 @@ static void execute_task_management(struct iscsi_cmnd *req)
|
||||
params.lun = (uint8_t *)&req_hdr->lun;
|
||||
params.lun_len = sizeof(req_hdr->lun);
|
||||
params.lun_set = 1;
|
||||
params.cmd_sn = req_hdr->cmd_sn;
|
||||
params.cmd_sn_set = 1;
|
||||
err = scst_rx_mgmt_fn(conn->session->scst_sess,
|
||||
¶ms);
|
||||
break;
|
||||
@@ -1985,16 +2008,23 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
|
||||
while (1) {
|
||||
session->exp_cmd_sn = ++cmd_sn;
|
||||
|
||||
spin_unlock(&session->sn_lock);
|
||||
if (unlikely(session->tm_active)) {
|
||||
if (before(cmd_sn, session->tm_sn)) {
|
||||
struct iscsi_conn *conn = cmnd->conn;
|
||||
|
||||
if (unlikely(session->tm_rsp != NULL)) {
|
||||
struct iscsi_conn *conn = cmnd->conn;
|
||||
spin_lock_bh(&conn->cmd_list_lock);
|
||||
__cmnd_abort(cmnd);
|
||||
spin_unlock_bh(&conn->cmd_list_lock);
|
||||
iscsi_cond_send_tm_resp(session->tm_rsp, 0);
|
||||
spin_unlock(&session->sn_lock);
|
||||
|
||||
spin_lock_bh(&conn->cmd_list_lock);
|
||||
__cmnd_abort(cmnd);
|
||||
spin_unlock_bh(&conn->cmd_list_lock);
|
||||
|
||||
spin_lock(&session->sn_lock);
|
||||
}
|
||||
iscsi_check_send_delayed_tm_resp(session);
|
||||
}
|
||||
|
||||
spin_unlock(&session->sn_lock);
|
||||
|
||||
iscsi_cmnd_exec(cmnd);
|
||||
|
||||
if (list_empty(&session->pending_list))
|
||||
@@ -2010,13 +2040,13 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
|
||||
}
|
||||
} else {
|
||||
cmnd->pending = 1;
|
||||
if (before(cmd_sn, session->exp_cmd_sn)) { /* close the conn */
|
||||
if (before(cmd_sn, session->exp_cmd_sn)) {
|
||||
PRINT_ERROR("unexpected cmd_sn (%u,%u)", cmd_sn,
|
||||
session->exp_cmd_sn);
|
||||
}
|
||||
|
||||
if (after(cmd_sn, session->exp_cmd_sn + iscsi_get_allowed_cmds(session))) {
|
||||
PRINT_ERROR("too large cmd_sn %u (exp_cmd_sn %u, "
|
||||
PRINT_INFO("Suspicious: too large cmd_sn %u (exp_cmd_sn %u, "
|
||||
"max_sn %u)", cmd_sn, session->exp_cmd_sn,
|
||||
iscsi_get_allowed_cmds(session));
|
||||
}
|
||||
@@ -2360,45 +2390,53 @@ out:
|
||||
return SCST_TGT_RES_SUCCESS;
|
||||
}
|
||||
|
||||
static void iscsi_cond_send_tm_resp(struct iscsi_cmnd *rsp, int force)
|
||||
/* Called under sn_lock */
|
||||
static bool iscsi_is_delay_tm_resp(struct iscsi_cmnd *rsp)
|
||||
{
|
||||
bool res = 0;
|
||||
struct iscsi_task_mgt_hdr *req_hdr =
|
||||
(struct iscsi_task_mgt_hdr *)&rsp->parent_req->pdu.bhs;
|
||||
(struct iscsi_task_mgt_hdr *)&rsp->parent_req->pdu.bhs;
|
||||
int function = req_hdr->function & ISCSI_FUNCTION_MASK;
|
||||
struct iscsi_session *sess = rsp->conn->session;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (!force) {
|
||||
spin_lock(&sess->sn_lock);
|
||||
switch(function) {
|
||||
case ISCSI_FUNCTION_ABORT_TASK_SET:
|
||||
case ISCSI_FUNCTION_CLEAR_TASK_SET:
|
||||
case ISCSI_FUNCTION_CLEAR_ACA:
|
||||
if (before(sess->exp_cmd_sn, req_hdr->cmd_sn)) {
|
||||
TRACE_MGMT_DBG("Delaying TM fn %x response, "
|
||||
"because not all affected commands "
|
||||
"received (rsp %p, cmd sn %x, exp sn "
|
||||
"%x)", function, rsp, req_hdr->cmd_sn,
|
||||
sess->exp_cmd_sn);
|
||||
sess->tm_rsp = rsp;
|
||||
spin_unlock(&sess->sn_lock);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock(&sess->sn_lock);
|
||||
switch(function) {
|
||||
default:
|
||||
if (before(sess->exp_cmd_sn, req_hdr->cmd_sn))
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rsp == sess->tm_rsp) {
|
||||
TRACE_MGMT_DBG("Sending delayed rsp %p (fn %x)", rsp, function);
|
||||
sess->tm_rsp = NULL;
|
||||
}
|
||||
iscsi_cmnd_init_write(rsp,
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Called under sn_lock, but might drop it inside, then reaquire */
|
||||
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess)
|
||||
{
|
||||
struct iscsi_cmnd *tm_rsp = sess->tm_rsp;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (tm_rsp == NULL)
|
||||
goto out;
|
||||
|
||||
if (iscsi_is_delay_tm_resp(tm_rsp))
|
||||
goto out;
|
||||
|
||||
TRACE(TRACE_MGMT_MINOR, "Sending delayed rsp %p", tm_rsp);
|
||||
|
||||
sess->tm_rsp = NULL;
|
||||
sess->tm_active = 0;
|
||||
|
||||
spin_unlock(&sess->sn_lock);
|
||||
|
||||
iscsi_cmnd_init_write(tm_rsp,
|
||||
ISCSI_INIT_WRITE_REMOVE_HASH | ISCSI_INIT_WRITE_WAKE);
|
||||
|
||||
spin_lock(&sess->sn_lock);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -2410,6 +2448,7 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status)
|
||||
struct iscsi_task_mgt_hdr *req_hdr =
|
||||
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
|
||||
struct iscsi_task_rsp_hdr *rsp_hdr;
|
||||
struct iscsi_session *sess = req->conn->session;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2429,8 +2468,26 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status)
|
||||
ISCSI_FUNCTION_TARGET_COLD_RESET)
|
||||
rsp->should_close_conn = 1;
|
||||
|
||||
iscsi_cond_send_tm_resp(rsp, 0);
|
||||
sBUG_ON(sess->tm_rsp != NULL);
|
||||
|
||||
spin_lock(&sess->sn_lock);
|
||||
if (iscsi_is_delay_tm_resp(rsp)) {
|
||||
TRACE(TRACE_MGMT_MINOR, "Delaying TM fn %x response %p "
|
||||
"(req %p), because not all affected commands received "
|
||||
"(cmd sn %d, exp sn %d)",
|
||||
req_hdr->function & ISCSI_FUNCTION_MASK, rsp, req,
|
||||
req_hdr->cmd_sn, sess->exp_cmd_sn);
|
||||
sess->tm_rsp = rsp;
|
||||
spin_unlock(&sess->sn_lock);
|
||||
goto out_release;
|
||||
}
|
||||
sess->tm_active = 0;
|
||||
spin_unlock(&sess->sn_lock);
|
||||
|
||||
iscsi_cmnd_init_write(rsp,
|
||||
ISCSI_INIT_WRITE_REMOVE_HASH | ISCSI_INIT_WRITE_WAKE);
|
||||
|
||||
out_release:
|
||||
req_cmnd_release(req);
|
||||
|
||||
TRACE_EXIT();
|
||||
|
||||
@@ -88,7 +88,7 @@ struct iscsi_session {
|
||||
struct iscsi_target *target;
|
||||
struct scst_session *scst_sess;
|
||||
|
||||
/* All 2 unprotected, since accessed only from a single read thread */
|
||||
/* Both unprotected, since accessed only from a single read thread */
|
||||
struct list_head pending_list;
|
||||
u32 next_ttt;
|
||||
|
||||
@@ -98,6 +98,9 @@ struct iscsi_session {
|
||||
spinlock_t sn_lock;
|
||||
u32 exp_cmd_sn; /* protected by sn_lock */
|
||||
|
||||
/* All 3 protected by sn_lock */
|
||||
unsigned int tm_active:1;
|
||||
u32 tm_sn;
|
||||
struct iscsi_cmnd *tm_rsp;
|
||||
|
||||
/* read only, if there are connection(s) */
|
||||
|
||||
@@ -136,6 +136,22 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
conn_abort(conn);
|
||||
|
||||
mutex_lock(&target->target_mutex);
|
||||
spin_lock(&session->sn_lock);
|
||||
if ((session->tm_rsp != NULL) && (session->tm_rsp->conn == conn)) {
|
||||
struct iscsi_cmnd *tm_rsp = session->tm_rsp;
|
||||
TRACE(TRACE_MGMT_MINOR, "Dropping delayed TM rsp %p", tm_rsp);
|
||||
session->tm_rsp = NULL;
|
||||
session->tm_active = 0;
|
||||
spin_unlock(&session->sn_lock);
|
||||
mutex_unlock(&target->target_mutex);
|
||||
|
||||
rsp_cmnd_release(tm_rsp);
|
||||
} else {
|
||||
spin_unlock(&session->sn_lock);
|
||||
mutex_unlock(&target->target_mutex);
|
||||
}
|
||||
|
||||
if (conn->read_state != RX_INIT_BHS) {
|
||||
req_cmnd_release_force(conn->read_cmnd, 0);
|
||||
conn->read_cmnd = NULL;
|
||||
@@ -181,10 +197,12 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
spin_lock_bh(&conn->cmd_list_lock);
|
||||
list_for_each_entry(cmnd, &conn->cmd_list, cmd_list_entry) {
|
||||
TRACE_CONN_CLOSE_DBG("cmd %p, scst_state %x, data_waiting "
|
||||
"%d, ref_cnt %d, parent_req %p", cmnd,
|
||||
cmnd->scst_state, cmnd->data_waiting,
|
||||
atomic_read(&cmnd->ref_cnt), cmnd->parent_req);
|
||||
TRACE_CONN_CLOSE_DBG("cmd %p, scst_state %x, scst_cmd "
|
||||
"state %d, data_waiting %d, ref_cnt %d, "
|
||||
"parent_req %p", cmnd, cmnd->scst_state,
|
||||
(cmnd->scst_cmd != NULL) ? cmnd->scst_cmd->state : -1,
|
||||
cmnd->data_waiting, atomic_read(&cmnd->ref_cnt),
|
||||
cmnd->parent_req);
|
||||
#ifdef NET_PAGE_CALLBACKS_DEFINED
|
||||
TRACE_CONN_CLOSE_DBG("net_ref_cnt %d, sg %p",
|
||||
atomic_read(&cmnd->net_ref_cnt), cmnd->sg);
|
||||
@@ -568,6 +586,8 @@ int istrd(void *arg)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Read thread started, PID %d", current->pid);
|
||||
|
||||
current->flags |= PF_NOFREEZE;
|
||||
|
||||
spin_lock_bh(&iscsi_rd_lock);
|
||||
@@ -598,6 +618,8 @@ int istrd(void *arg)
|
||||
*/
|
||||
sBUG_ON(!list_empty(&iscsi_rd_list));
|
||||
|
||||
PRINT_INFO("Read thread PID %d finished", current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
}
|
||||
@@ -1072,6 +1094,8 @@ int istwr(void *arg)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Write thread started, PID %d", current->pid);
|
||||
|
||||
current->flags |= PF_NOFREEZE;
|
||||
|
||||
spin_lock_bh(&iscsi_wr_lock);
|
||||
@@ -1102,6 +1126,8 @@ int istwr(void *arg)
|
||||
*/
|
||||
sBUG_ON(!list_empty(&iscsi_wr_list));
|
||||
|
||||
PRINT_INFO("Write thread PID %d finished", current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ void text_key_add(struct connection *conn, char *key, char *value)
|
||||
}
|
||||
conn->rsp.data = conn->rsp_buffer;
|
||||
}
|
||||
if (conn->rwsize + len > INCOMING_BUFSIZE) {
|
||||
if (conn->rsp.datasize + len > INCOMING_BUFSIZE) {
|
||||
log_warning("Dropping key (%s=%s)", key, value);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
#include <scst_const.h>
|
||||
|
||||
#define DEV_USER_NAME "scst_user"
|
||||
#define DEV_USER_NAME "scst_user"
|
||||
#define DEV_USER_PATH "/dev/"
|
||||
#define DEV_USER_VERSION 962
|
||||
#define DEV_USER_VERSION 963
|
||||
|
||||
/*
|
||||
* Chosen so sizeof(scst_user_sess) <= sizeof(scst_user_scsi_cmd_exec)
|
||||
@@ -137,6 +137,8 @@ struct scst_user_scsi_cmd_parse
|
||||
uint8_t expected_values_set;
|
||||
uint8_t expected_data_direction;
|
||||
int32_t expected_transfer_len;
|
||||
|
||||
uint32_t sn;
|
||||
};
|
||||
|
||||
struct scst_user_scsi_cmd_alloc_mem
|
||||
@@ -150,6 +152,8 @@ struct scst_user_scsi_cmd_alloc_mem
|
||||
|
||||
uint8_t queue_type;
|
||||
uint8_t data_direction;
|
||||
|
||||
uint32_t sn;
|
||||
};
|
||||
|
||||
struct scst_user_scsi_cmd_exec
|
||||
@@ -168,6 +172,8 @@ struct scst_user_scsi_cmd_exec
|
||||
uint8_t partial;
|
||||
uint32_t timeout;
|
||||
|
||||
uint32_t sn;
|
||||
|
||||
uint32_t parent_cmd_h;
|
||||
int32_t parent_cmd_data_len;
|
||||
uint32_t partial_offset;
|
||||
@@ -193,6 +199,8 @@ struct scst_user_tm
|
||||
aligned_u64 sess_h;
|
||||
uint32_t fn;
|
||||
uint32_t cmd_h_to_abort;
|
||||
uint32_t cmd_sn;
|
||||
uint8_t cmd_sn_set;
|
||||
};
|
||||
|
||||
struct scst_user_get_cmd
|
||||
|
||||
@@ -596,6 +596,7 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd)
|
||||
(cmd->sg_cnt << PAGE_SHIFT) : cmd->bufflen;
|
||||
ucmd->user_cmd.alloc_cmd.queue_type = cmd->queue_type;
|
||||
ucmd->user_cmd.alloc_cmd.data_direction = cmd->data_direction;
|
||||
ucmd->user_cmd.alloc_cmd.sn = cmd->tgt_sn;
|
||||
|
||||
dev_user_add_to_ready(ucmd);
|
||||
|
||||
@@ -722,6 +723,7 @@ static int dev_user_parse(struct scst_cmd *cmd)
|
||||
cmd->expected_data_direction;
|
||||
ucmd->user_cmd.parse_cmd.expected_transfer_len =
|
||||
cmd->expected_transfer_len;
|
||||
ucmd->user_cmd.parse_cmd.sn = cmd->tgt_sn;
|
||||
ucmd->state = UCMD_STATE_PARSING;
|
||||
dev_user_add_to_ready(ucmd);
|
||||
res = SCST_CMD_STATE_STOP;
|
||||
@@ -809,6 +811,7 @@ static int dev_user_exec(struct scst_cmd *cmd)
|
||||
ucmd->user_cmd.exec_cmd.data_direction = cmd->data_direction;
|
||||
ucmd->user_cmd.exec_cmd.partial = 0;
|
||||
ucmd->user_cmd.exec_cmd.timeout = cmd->timeout;
|
||||
ucmd->user_cmd.exec_cmd.sn = cmd->tgt_sn;
|
||||
|
||||
ucmd->state = UCMD_STATE_EXECING;
|
||||
|
||||
@@ -2126,6 +2129,8 @@ static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
||||
ucmd->user_cmd.subcode = SCST_USER_TASK_MGMT;
|
||||
ucmd->user_cmd.tm_cmd.sess_h = (unsigned long)tgt_dev;
|
||||
ucmd->user_cmd.tm_cmd.fn = mcmd->fn;
|
||||
ucmd->user_cmd.tm_cmd.cmd_sn = mcmd->cmd_sn;
|
||||
ucmd->user_cmd.tm_cmd.cmd_sn_set = mcmd->cmd_sn_set;
|
||||
|
||||
if (mcmd->cmd_to_abort != NULL) {
|
||||
ucmd_to_abort = (struct scst_user_cmd*)mcmd->cmd_to_abort->dh_priv;
|
||||
@@ -2990,6 +2995,8 @@ static int dev_user_cleanup_thread(void *arg)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Cleanup thread started, PID %d", current->pid);
|
||||
|
||||
current->flags |= PF_NOFREEZE;
|
||||
|
||||
spin_lock(&cleanup_lock);
|
||||
@@ -3027,6 +3034,8 @@ restart:
|
||||
*/
|
||||
sBUG_ON(!list_empty(&cleanup_list));
|
||||
|
||||
PRINT_INFO("Cleanup thread PID %d finished", current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
+5
-1
@@ -3322,13 +3322,17 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
/* No locks */
|
||||
void tm_dbg_task_mgmt(const char *fn, int force)
|
||||
void tm_dbg_task_mgmt(struct scst_tgt_dev *tgt_dev, const char *fn, int force)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!tm_dbg_flags.tm_dbg_active)
|
||||
goto out;
|
||||
|
||||
if ((tgt_dev != NULL) && !test_bit(SCST_TGT_DEV_UNDER_TM_DBG,
|
||||
&tgt_dev->tgt_dev_flags))
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
if ((tm_dbg_state != TM_DBG_STATE_OFFLINE) || force) {
|
||||
TRACE_MGMT_DBG("%s: freeing %d delayed cmds", fn,
|
||||
|
||||
@@ -512,7 +512,8 @@ extern void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev);
|
||||
extern void tm_dbg_check_released_cmds(void);
|
||||
extern int tm_dbg_check_cmd(struct scst_cmd *cmd);
|
||||
extern void tm_dbg_release_cmd(struct scst_cmd *cmd);
|
||||
extern void tm_dbg_task_mgmt(const char *fn, int force);
|
||||
extern void tm_dbg_task_mgmt(struct scst_tgt_dev *tgt_dev, const char *fn,
|
||||
int force);
|
||||
extern int tm_dbg_is_release(void);
|
||||
#else
|
||||
static inline void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
@@ -524,7 +525,8 @@ static inline int tm_dbg_check_cmd(struct scst_cmd *cmd)
|
||||
return 0;
|
||||
}
|
||||
static inline void tm_dbg_release_cmd(struct scst_cmd *cmd) {}
|
||||
static inline void tm_dbg_task_mgmt(const char *fn, int force) {}
|
||||
static inline void tm_dbg_task_mgmt(struct scst_tgt_dev *tgt_dev, const char *fn,
|
||||
int force) {}
|
||||
static inline int tm_dbg_is_release(void)
|
||||
{
|
||||
return 0;
|
||||
|
||||
+51
-23
@@ -448,6 +448,14 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
if (unlikely(state == SCST_CMD_STATE_PRE_XMIT_RESP))
|
||||
goto set_res;
|
||||
|
||||
if (unlikely((cmd->bufflen == 0) &&
|
||||
(cmd->op_flags & SCST_UNKNOWN_LENGTH))) {
|
||||
PRINT_ERROR("Unknown data transfer length for opcode 0x%x "
|
||||
"(handler %s, target %s)", cmd->cdb[0],
|
||||
dev->handler->name, cmd->tgtt->name);
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
#ifdef EXTRACHECKS
|
||||
if ((cmd->bufflen != 0) &&
|
||||
((cmd->data_direction == SCST_DATA_NONE) ||
|
||||
@@ -2854,6 +2862,8 @@ int scst_init_cmd_thread(void *arg)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Init thread started, PID %d", current->pid);
|
||||
|
||||
current->flags |= PF_NOFREEZE;
|
||||
|
||||
set_user_nice(current, -20);
|
||||
@@ -2887,6 +2897,8 @@ int scst_init_cmd_thread(void *arg)
|
||||
*/
|
||||
sBUG_ON(!list_empty(&scst_init_cmd_list));
|
||||
|
||||
PRINT_INFO("Init thread PID %d finished", current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
}
|
||||
@@ -3053,6 +3065,8 @@ int scst_cmd_thread(void *arg)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Processing thread started, PID %d", current->pid);
|
||||
|
||||
#if 0
|
||||
set_user_nice(current, 10);
|
||||
#endif
|
||||
@@ -3101,6 +3115,8 @@ int scst_cmd_thread(void *arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
PRINT_INFO("Processing thread PID %d finished", current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
}
|
||||
@@ -3659,8 +3675,9 @@ out:
|
||||
static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
int res, rc;
|
||||
struct scst_device *dev, *d;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct scst_device *dev;
|
||||
struct scst_acg *acg = mcmd->sess->acg;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
int cont, c;
|
||||
LIST_HEAD(host_devs);
|
||||
|
||||
@@ -3673,20 +3690,12 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
struct scst_device *d;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
int found = 0;
|
||||
|
||||
/* Skip local SCSI devices */
|
||||
if (dev->handler == &scst_null_devtype) {
|
||||
/*
|
||||
* Generally we shouldn't reset not exported devices,
|
||||
* but what if a backstorage SCSI disk hung? Let's
|
||||
* reset it too.
|
||||
*/
|
||||
if ((dev->scsi_dev != NULL) &&
|
||||
(dev->scsi_dev->type != TYPE_DISK))
|
||||
continue;
|
||||
}
|
||||
dev = acg_dev->dev;
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
__scst_block_dev(dev);
|
||||
@@ -3744,14 +3753,15 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
|
||||
#endif
|
||||
}
|
||||
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
dev = acg_dev->dev;
|
||||
if (dev->scsi_dev != NULL)
|
||||
dev->scsi_dev->was_reset = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
tm_dbg_task_mgmt("TARGET RESET", 0);
|
||||
tm_dbg_task_mgmt(mcmd->mcmd_tgt_dev, "TARGET RESET", 0);
|
||||
res = scst_set_mcmd_next_state(mcmd);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -3792,7 +3802,7 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
|
||||
}
|
||||
|
||||
out_tm_dbg:
|
||||
tm_dbg_task_mgmt("LUN RESET", 0);
|
||||
tm_dbg_task_mgmt(mcmd->mcmd_tgt_dev, "LUN RESET", 0);
|
||||
res = scst_set_mcmd_next_state(mcmd);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -3857,9 +3867,9 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
|
||||
int res;
|
||||
int i;
|
||||
struct scst_tgt *tgt = mcmd->sess->tgt;
|
||||
struct scst_acg *acg = mcmd->sess->acg;
|
||||
struct scst_session *sess;
|
||||
struct scst_device *dev;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -3875,7 +3885,9 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
struct scst_device *dev = acg_dev->dev;
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
__scst_block_dev(dev);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
@@ -3885,6 +3897,7 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
|
||||
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
struct list_head *sess_tgt_dev_list_head =
|
||||
&sess->sess_tgt_dev_list_hash[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
int rc;
|
||||
@@ -4020,12 +4033,19 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
|
||||
case SCST_TARGET_RESET:
|
||||
case SCST_ABORT_ALL_TASKS:
|
||||
case SCST_NEXUS_LOSS:
|
||||
{
|
||||
struct scst_acg *acg = mcmd->sess->acg;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list,
|
||||
acg_dev_list_entry) {
|
||||
dev = acg_dev->dev;
|
||||
scst_unblock_dev(dev);
|
||||
}
|
||||
mutex_unlock(&scst_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCST_NEXUS_LOSS_SESS:
|
||||
case SCST_ABORT_ALL_TASKS_SESS:
|
||||
@@ -4115,6 +4135,8 @@ int scst_mgmt_cmd_thread(void *arg)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Task management thread started, PID %d", current->pid);
|
||||
|
||||
current->flags |= PF_NOFREEZE;
|
||||
|
||||
set_user_nice(current, -20);
|
||||
@@ -4174,6 +4196,8 @@ int scst_mgmt_cmd_thread(void *arg)
|
||||
*/
|
||||
sBUG_ON(!list_empty(&scst_active_mgmt_cmd_list));
|
||||
|
||||
PRINT_INFO("Task management thread PID %d finished", current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
}
|
||||
@@ -4311,7 +4335,7 @@ int scst_rx_mgmt_fn(struct scst_session *sess,
|
||||
|
||||
TRACE((params->fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
|
||||
"sess=%p, fn %x, tag_set %d, tag %Ld, lun_set %d, "
|
||||
"lun=%Ld, cmd_sn_set %d, cmd_sn %x", sess, params->fn,
|
||||
"lun=%Ld, cmd_sn_set %d, cmd_sn %d", sess, params->fn,
|
||||
params->tag_set, params->tag, params->lun_set,
|
||||
(uint64_t)mcmd->lun, params->cmd_sn_set, params->cmd_sn);
|
||||
|
||||
@@ -4551,7 +4575,7 @@ void scst_unregister_session(struct scst_session *sess, int wait,
|
||||
|
||||
spin_unlock_irqrestore(&scst_mgmt_lock, flags);
|
||||
|
||||
tm_dbg_task_mgmt("UNREGISTER SESSION", 1);
|
||||
tm_dbg_task_mgmt(NULL, "UNREGISTER SESSION", 1);
|
||||
|
||||
scst_sess_put(sess);
|
||||
|
||||
@@ -4619,6 +4643,8 @@ int scst_mgmt_thread(void *arg)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Management thread started, PID %d", current->pid);
|
||||
|
||||
current->flags |= PF_NOFREEZE;
|
||||
|
||||
set_user_nice(current, -20);
|
||||
@@ -4700,6 +4726,8 @@ int scst_mgmt_thread(void *arg)
|
||||
sBUG_ON(!list_empty(&scst_sess_init_list));
|
||||
sBUG_ON(!list_empty(&scst_sess_shut_list));
|
||||
|
||||
PRINT_INFO("Management thread PID %d finished", current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user