A huge chunk of related to each other changes, which had to be tested together.

iSCSI-SCST: A huge improvements in errors recovery and iSCSI RFC complaince as well as performance. Also:

 - Fixes and improvements for MaxOutstandingR2T>1

 - Flow control tracing added.

 - Cleanups

SCST core:

 - Now for scst_cmd_init_stage1_done() commands preprocessing_done() is always called before xmit_response(), even in case of abort or error.

 - Fixed recently introduced bug, which can lead to sending responses for aborted commands after reply on the corresponding TM command already sent.

 - Flow control tracing added.

 - Now it is possible to call functions setting commands execution status (e.g., scst_set_cmd_error_status()) several times for the same command. Only the first call will be completed, other calls - ignored.

 - All commands are counted and shown in proc/sysfs now. Before only active, i.e. not yet executed commands, were counted and shown there.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1431 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2010-01-06 13:02:22 +00:00
parent 6a523b3c13
commit 05d1bbfedc
17 changed files with 1561 additions and 969 deletions

View File

@@ -1,5 +1,3 @@
- Fix support of ranges in parameters negotiation.
- Fix SNACK command handling. Currently it violates iSCSI RFC.
- Minor "ToDo"'s spread in the code.

View File

@@ -26,7 +26,6 @@
#define ISCSI_PROC_LOG_ENTRY_NAME "trace_level"
static struct scst_trace_log iscsi_local_trace_tbl[] = {
{ TRACE_D_READ, "d_read" },
{ TRACE_D_WRITE, "d_write" },
{ TRACE_CONN_OC, "conn" },
{ TRACE_CONN_OC_DBG, "conn_dbg" },
@@ -605,7 +604,7 @@ void iscsi_dump_pdu(struct iscsi_pdu *pdu)
buf = (void *)&pdu->bhs;
printk(KERN_DEBUG "BHS: (%p,%zd)\n", buf, sizeof(pdu->bhs));
for (i = 0; i < sizeof(pdu->bhs); i++)
for (i = 0; i < (int)sizeof(pdu->bhs); i++)
iscsi_dump_char(*buf++, text, &pos);
iscsi_dump_char(-1, text, &pos);
@@ -618,4 +617,25 @@ void iscsi_dump_pdu(struct iscsi_pdu *pdu)
printk(KERN_DEBUG "Data: (%d)\n", pdu->datasize);
}
}
unsigned long iscsi_get_flow_ctrl_or_mgmt_dbg_log_flag(struct iscsi_cmnd *cmnd)
{
unsigned long flag;
if (cmnd->cmd_req != NULL)
cmnd = cmnd->cmd_req;
if (cmnd->scst_cmd == NULL)
flag = TRACE_MGMT_DEBUG;
else {
int status = scst_cmd_get_status(cmnd->scst_cmd);
if ((status == SAM_STAT_TASK_SET_FULL) ||
(status == SAM_STAT_BUSY))
flag = TRACE_FLOW_CONTROL;
else
flag = TRACE_MGMT_DEBUG;
}
return flag;
}
#endif /* CONFIG_SCST_DEBUG */

View File

@@ -372,6 +372,9 @@ static void iscsi_write_space_ready(struct sock *sk)
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();
@@ -379,32 +382,107 @@ static void conn_rsp_timer_fn(unsigned long arg)
spin_lock_bh(&conn->write_list_lock);
if (!list_empty(&conn->written_list)) {
struct iscsi_cmnd *wr_cmd = list_entry(conn->written_list.next,
struct iscsi_cmnd, written_list_entry);
if (!list_empty(&conn->write_timeout_list)) {
cmnd = list_entry(conn->write_timeout_list.next,
struct iscsi_cmnd, write_timeout_list_entry);
if (unlikely(time_after_eq(jiffies, wr_cmd->write_timeout))) {
if (unlikely(time_after_eq(j,
cmnd->write_start + ISCSI_RSP_TIMEOUT))) {
if (!conn->closing) {
PRINT_ERROR("Timeout sending data to initiator"
" %s (SID %llx), closing connection",
PRINT_ERROR("Timeout sending data/waiting "
"for reply to/from initiator "
"%s (SID %llx), closing connection",
conn->session->initiator_name,
(long long unsigned int)
conn->session->sid);
/*
* We must call mark_conn_closed() outside of
* write_list_lock or we will have a circular
* locking dependency with iscsi_rd_lock.
*/
spin_unlock_bh(&conn->write_list_lock);
mark_conn_closed(conn);
goto out;
}
} else {
} else if (!timer_pending(&conn->rsp_timer) ||
time_after(conn->rsp_timer.expires, timeout_time)) {
TRACE_DBG("Restarting timer on %ld (conn %p)",
wr_cmd->write_timeout, conn);
timeout_time, conn);
/*
* Timer might have been restarted while we were
* entering here.
*/
mod_timer(&conn->rsp_timer, wr_cmd->write_timeout);
mod_timer(&conn->rsp_timer, timeout_time);
}
}
spin_unlock_bh(&conn->write_list_lock);
if (unlikely(conn->conn_tm_active)) {
TRACE_MGMT_DBG("TM active: making conn %p RD active", conn);
iscsi_make_conn_rd_active(conn);
}
out:
TRACE_EXIT();
return;
}
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;
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);
again:
spin_lock_bh(&iscsi_rd_lock);
spin_lock(&conn->write_list_lock);
aborted_cmds_pending = false;
list_for_each_entry(cmnd, &conn->write_timeout_list,
write_timeout_list_entry) {
if (test_bit(ISCSI_CMD_ABORTED, &cmnd->prelim_compl_flags)) {
TRACE_DBG_FLAG(force ? TRACE_CONN_OC_DBG : TRACE_MGMT_DEBUG,
"Checking aborted cmnd %p (scst_state %d, "
"on_write_timeout_list %d, write_start %ld, "
"r2t_len_to_receive %d)", cmnd,
cmnd->scst_state, cmnd->on_write_timeout_list,
cmnd->write_start, cmnd->r2t_len_to_receive);
if ((cmnd->r2t_len_to_receive != 0) &&
(time_after_eq(j, cmnd->write_start + ISCSI_TM_DATA_WAIT_TIMEOUT) ||
force)) {
spin_unlock(&conn->write_list_lock);
spin_unlock_bh(&iscsi_rd_lock);
iscsi_fail_data_waiting_cmnd(cmnd);
goto again;
}
aborted_cmds_pending = true;
}
}
if (aborted_cmds_pending) {
if (!force &&
(!timer_pending(&conn->rsp_timer) ||
time_after(conn->rsp_timer.expires, timeout_time))) {
TRACE_MGMT_DBG("Mod timer on %ld (conn %p)",
timeout_time, conn);
mod_timer(&conn->rsp_timer, timeout_time);
}
} else {
TRACE_MGMT_DBG("Clearing conn_tm_active for conn %p", conn);
conn->conn_tm_active = 0;
}
spin_unlock(&conn->write_list_lock);
spin_unlock_bh(&iscsi_rd_lock);
TRACE_EXIT();
return;
}
@@ -515,7 +593,7 @@ static int conn_free(struct iscsi_conn *conn)
sBUG_ON(atomic_read(&conn->conn_ref_cnt) != 0);
sBUG_ON(!list_empty(&conn->cmd_list));
sBUG_ON(!list_empty(&conn->write_list));
sBUG_ON(!list_empty(&conn->written_list));
sBUG_ON(!list_empty(&conn->write_timeout_list));
sBUG_ON(conn->conn_reinst_successor != NULL);
sBUG_ON(!test_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags));
@@ -599,7 +677,7 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
INIT_LIST_HEAD(&conn->cmd_list);
spin_lock_init(&conn->write_list_lock);
INIT_LIST_HEAD(&conn->write_list);
INIT_LIST_HEAD(&conn->written_list);
INIT_LIST_HEAD(&conn->write_timeout_list);
setup_timer(&conn->rsp_timer, conn_rsp_timer_fn, (unsigned long)conn);
init_waitqueue_head(&conn->read_state_waitQ);
init_completion(&conn->ready_to_free);

View File

@@ -157,12 +157,14 @@ int digest_rx_data(struct iscsi_cmnd *cmnd)
u32 offset, crc;
int res = 0;
if (unlikely(cmnd->rejected))
goto out;
switch (cmnd_opcode(cmnd)) {
case ISCSI_OP_SCSI_DATA_OUT:
req = cmnd->cmd_req;
if (unlikely(req == NULL)) {
/* It can be for prelim completed commands */
req = cmnd;
goto out;
}
req_hdr = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs;
offset = be32_to_cpu(req_hdr->buffer_offset);
break;
@@ -172,6 +174,16 @@ int digest_rx_data(struct iscsi_cmnd *cmnd)
offset = 0;
}
/*
* We need to skip the digest check for prelim completed commands,
* because we use shared data buffer for them, so, most likely, the
* check will fail. Plus, for such commands we sometimes don't have
* sg_cnt set correctly (cmnd_prepare_get_rejected_cmd_data() doesn't
* do it).
*/
if (unlikely(req->prelim_compl_flags != 0))
goto out;
crc = digest_data(req, cmnd->pdu.datasize, offset,
cmnd->conn->rpadding);

File diff suppressed because it is too large Load Diff

View File

@@ -29,8 +29,9 @@
#include "iscsi_dbg.h"
#define iscsi_sense_crc_error ABORTED_COMMAND, 0x47, 0x5
#define iscsi_sense_unexpected_unsolicited_data ABORTED_COMMAND, 0xC, 0xC
#define iscsi_sense_crc_error ABORTED_COMMAND, 0x47, 0x05
#define iscsi_sense_unexpected_unsolicited_data ABORTED_COMMAND, 0x0C, 0x0C
#define iscsi_sense_incorrect_amount_of_data ABORTED_COMMAND, 0x0C, 0x0D
struct iscsi_sess_param {
int initial_r2t;
@@ -120,8 +121,13 @@ struct iscsi_session {
/* Read only, if there are connection(s) */
struct iscsi_sess_param sess_param;
spinlock_t cmnd_hash_lock;
struct list_head cmnd_hash[1 << ISCSI_HASH_ORDER];
/*
* In some corner cases commands can be deleted from the hash
* not from the corresponding read thread. So, let's simplify
* errors recovery and have this lock.
*/
spinlock_t cmnd_data_wait_hash_lock;
struct list_head cmnd_data_wait_hash[1 << ISCSI_HASH_ORDER];
struct list_head conn_list; /* protected by target_mutex */
@@ -170,7 +176,7 @@ struct iscsi_conn {
/* List of data pdus to be sent, protected by write_list_lock */
struct list_head write_list;
/* List of data pdus being sent, protected by write_list_lock */
struct list_head written_list;
struct list_head write_timeout_list;
struct timer_list rsp_timer;
@@ -208,13 +214,14 @@ struct iscsi_conn {
int hdigest_type;
int ddigest_type;
/* All 5 protected by iscsi_rd_lock */
/* All 6 protected by iscsi_rd_lock */
unsigned short rd_state;
unsigned short rd_data_ready:1;
/* Let's save some cache footprint by putting them here */
unsigned short closing:1;
unsigned short active_close:1;
unsigned short deleting:1;
unsigned short conn_tm_active:1;
struct list_head rd_list_entry;
@@ -264,37 +271,38 @@ struct iscsi_pdu {
typedef void (iscsi_show_info_t)(struct seq_file *seq,
struct iscsi_target *target);
/** Command's states **/
/** Commands' states **/
/* New command and SCST processes it */
#define ISCSI_CMD_STATE_NEW 0
#define ISCSI_CMD_STATE_NEW 0
/* SCST processes cmd after scst_rx_cmd() */
#define ISCSI_CMD_STATE_RX_CMD 1
#define ISCSI_CMD_STATE_RX_CMD 1
/* The command returned from preprocessing_done() */
#define ISCSI_CMD_STATE_AFTER_PREPROC 2
#define ISCSI_CMD_STATE_AFTER_PREPROC 2
/* The command is waiting for session or connection reinstatement finished */
#define ISCSI_CMD_STATE_REINST_PENDING 3
#define ISCSI_CMD_STATE_REINST_PENDING 3
/* scst_restart_cmd() called and SCST processing it */
#define ISCSI_CMD_STATE_RESTARTED 4
#define ISCSI_CMD_STATE_RESTARTED 4
/* SCST done processing */
#define ISCSI_CMD_STATE_PROCESSED 5
#define ISCSI_CMD_STATE_PROCESSED 5
/* AEN processing */
#define ISCSI_CMD_STATE_AEN 6
#define ISCSI_CMD_STATE_AEN 6
/** Command's reject reasons **/
#define ISCSI_REJECT_SCSI_CMD 1
#define ISCSI_REJECT_CMD 2
#define ISCSI_REJECT_DATA 3
/* Out of SCST core preliminary completed */
#define ISCSI_CMD_STATE_OUT_OF_SCST_PRELIM_COMPL 7
/*
* Most of the fields don't need any protection, since accessed from only a
* single thread, except where noted.
*
* ToDo: Eventually divide request and response structures in 2 separate
* structures and stop this IET-derived garbage.
*/
struct iscsi_cmnd {
struct iscsi_conn *conn;
@@ -310,31 +318,41 @@ struct iscsi_cmnd {
unsigned int own_sg:1;
unsigned int on_write_list:1;
unsigned int write_processing_started:1;
unsigned int data_waiting:1;
unsigned int force_cleanup_done:1;
unsigned int dec_active_cmnds:1;
unsigned int ddigest_checked:1;
unsigned int rejected:1;
unsigned int reject_reason:2;
#ifdef CONFIG_SCST_EXTRACHECKS
unsigned int on_rx_digest_list:1;
unsigned int release_called:1;
#endif
/* It's async. with the above flags */
volatile unsigned int tm_aborted;
/*
* We suppose that preliminary commands completion is tested by
* comparing prelim_compl_flags with 0. Otherwise, because of the
* gap between setting different flags a race is possible,
* like sending command in SCST core as PRELIM_COMPLETED, while it
* wasn't aborted in it yet and have as the result a wrong success
* status sent to the initiator.
*/
#define ISCSI_CMD_ABORTED 0
#define ISCSI_CMD_PRELIM_COMPLETED 1
unsigned long prelim_compl_flags;
struct list_head hash_list_entry;
spinlock_t rsp_cmd_lock; /* BH lock */
/*
* Unions are for readability and grepability and to save some
* cache footprint.
*/
union {
/* Protected by rsp_cmd_lock */
/*
* Used only to abort not yet sent responses. Usage in
* cmnd_done() is only a side effect to have a lockless
* accesss to this list from always only a single thread
* at any time. So, all responses live in the parent
* until it has the last reference put.
*/
struct list_head rsp_cmd_list;
struct list_head rsp_cmd_list_entry;
};
@@ -346,12 +364,12 @@ struct iscsi_cmnd {
union {
struct list_head write_list_entry;
struct list_head written_list_entry;
struct list_head write_timeout_list_entry;
};
/* Both modified only from single write thread */
unsigned int on_written_list:1;
unsigned long write_timeout;
unsigned int on_write_timeout_list:1;
unsigned long write_start;
/*
* All unprotected, since could be accessed from only a single
@@ -375,7 +393,9 @@ struct iscsi_cmnd {
struct scst_cmd *scst_cmd;
struct scst_aen *scst_aen;
};
int read_size;
unsigned int read_size;
struct iscsi_cmnd *main_rsp;
};
/* Response only fields */
@@ -396,21 +416,29 @@ struct iscsi_cmnd {
int sg_cnt;
unsigned int bufflen;
u32 r2t_sn;
u32 r2t_length;
u32 is_unsolicited_data;
unsigned int r2t_len_to_receive;
unsigned int r2t_len_to_send;
unsigned int outstanding_r2t;
u32 target_task_tag;
u32 outstanding_r2t;
u32 hdigest;
u32 ddigest;
struct list_head cmd_list_entry;
};
/* Flags for req_cmnd_release_force() */
#define ISCSI_FORCE_RELEASE_WRITE 1
/**
** 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)
extern struct mutex target_mgmt_mutex;
@@ -432,11 +460,12 @@ extern int cmnd_rx_continue(struct iscsi_cmnd *req);
extern void cmnd_rx_end(struct iscsi_cmnd *);
extern void cmnd_tx_start(struct iscsi_cmnd *);
extern void cmnd_tx_end(struct iscsi_cmnd *);
extern void req_cmnd_release_force(struct iscsi_cmnd *req, int flags);
extern void req_cmnd_release_force(struct iscsi_cmnd *req);
extern void rsp_cmnd_release(struct iscsi_cmnd *);
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);
/* conn.c */
extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
@@ -447,17 +476,16 @@ extern int conn_del(struct iscsi_session *, struct iscsi_kern_conn_info *);
extern int conn_free(struct iscsi_conn *);
#endif
extern void iscsi_make_conn_rd_active(struct iscsi_conn *conn);
#define ISCSI_CONN_ACTIVE_CLOSE 1
#define ISCSI_CONN_DELETING 2
extern void __mark_conn_closed(struct iscsi_conn *, int);
extern void mark_conn_closed(struct iscsi_conn *);
extern void iscsi_make_conn_wr_active(struct iscsi_conn *);
#ifdef CONFIG_SCST_PROC
extern void conn_info_show(struct seq_file *, struct iscsi_session *);
#endif
extern void iscsi_check_tm_data_wait_timeouts(struct iscsi_conn *conn,
bool force);
/* nthread.c */
extern int iscsi_send(struct iscsi_conn *conn);
@@ -468,6 +496,7 @@ extern void iscsi_put_page_callback(struct page *page);
extern int istrd(void *arg);
extern int istwr(void *arg);
extern void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd);
extern void req_add_to_write_timeout_list(struct iscsi_cmnd *req);
/* target.c */
#ifndef CONFIG_SCST_PROC
@@ -598,7 +627,10 @@ static inline void cmnd_put(struct iscsi_cmnd *cmnd)
static inline void cmd_add_on_write_list(struct iscsi_conn *conn,
struct iscsi_cmnd *cmnd)
{
TRACE_DBG("%p", cmnd);
TRACE_DBG("cmnd %p", cmnd);
/* See comment in iscsi_restart_cmnd() */
EXTRACHECKS_BUG_ON(cmnd->parent_req->hashed &&
(cmnd_opcode(cmnd) != ISCSI_OP_R2T));
list_add_tail(&cmnd->write_list_entry, &conn->write_list);
cmnd->on_write_list = 1;
}

View File

@@ -20,18 +20,12 @@
#include <scst_debug.h>
#define TRACE_D_READ 0x80000000
#define TRACE_D_WRITE 0x40000000
#define TRACE_CONN_OC 0x20000000
#define TRACE_D_IOV 0x10000000
#define TRACE_D_DUMP_PDU 0x08000000
#define TRACE_NET_PG 0x04000000
#define TRACE_CONN_OC_DBG 0x02000000
#define TRACE_D_DATA (TRACE_D_READ | TRACE_D_WRITE)
#define TRACE_ALL_NO_DATA \
(TRACE_ALL & ~TRACE_D_IOV & ~TRACE_D_DUMP_PDU & ~TRACE_D_DATA)
#define TRACE_D_WRITE 0x80000000
#define TRACE_CONN_OC 0x40000000
#define TRACE_D_IOV 0x20000000
#define TRACE_D_DUMP_PDU 0x10000000
#define TRACE_NET_PG 0x08000000
#define TRACE_CONN_OC_DBG 0x04000000
#ifdef CONFIG_SCST_DEBUG
#define ISCSI_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_LINE | TRACE_PID | \
@@ -44,9 +38,13 @@
#ifdef CONFIG_SCST_DEBUG
struct iscsi_pdu;
struct iscsi_cmnd;
extern void iscsi_dump_pdu(struct iscsi_pdu *pdu);
extern unsigned long iscsi_get_flow_ctrl_or_mgmt_dbg_log_flag(
struct iscsi_cmnd *cmnd);
#else
#define iscsi_dump_pdu(x) do {} while (0)
#define iscsi_get_flow_ctrl_or_mgmt_dbg_log_flag(x) do {} while (0)
#endif
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
@@ -54,20 +52,9 @@ extern unsigned long iscsi_trace_flag;
#define trace_flag iscsi_trace_flag
#endif
#ifdef CONFIG_SCST_DEBUG
#define TRACE_CONN_CLOSE(args...) TRACE(TRACE_CONN_OC, args)
#define TRACE_CONN_CLOSE(args...) TRACE_DBG_FLAG(TRACE_DEBUG|TRACE_CONN_OC, args)
#define TRACE_CONN_CLOSE_DBG(args...) TRACE(TRACE_CONN_OC_DBG, args)
#define TRACE_NET_PAGE(args...) TRACE(TRACE_NET_PG, args)
#define TRACE_WRITE(args...) TRACE(TRACE_D_WRITE, args)
#define TRACE_READ(args...) TRACE(TRACE_D_READ, args)
#else /* CONFIG_SCST_DEBUG */
#define TRACE_CONN_CLOSE(format, args...) {}
#define TRACE_CONN_CLOSE_DBG(format, args...) {}
#define TRACE_NET_PAGE(format, args...) {}
#define TRACE_WRITE(args...) {}
#define TRACE_READ(args...) {}
#endif
#define TRACE_NET_PAGE(args...) TRACE_DBG_FLAG(TRACE_NET_PG, args)
#define TRACE_WRITE(args...) TRACE_DBG_FLAG(TRACE_DEBUG|TRACE_D_WRITE, args)
#endif

View File

@@ -511,7 +511,6 @@ struct iscsi_nop_in_hdr {
#define ISCSI_RESERVED_TAG (0xffffffffU)
#define cmnd_hdr(cmnd) ((struct iscsi_scsi_cmd_hdr *) (&((cmnd)->pdu.bhs)))
#define cmnd_ttt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.ttt)
#define cmnd_itt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.itt)
#define cmnd_opcode(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OPCODE_MASK)
#define cmnd_scsicode(cmnd) (cmnd_hdr((cmnd))->scb[0])

View File

@@ -78,11 +78,12 @@ again:
struct iscsi_cmnd *rsp;
int restart = 0;
TRACE_CONN_CLOSE_DBG("cmd %p, scst_state %x, data_waiting %d, "
"ref_cnt %d, parent_req %p, net_ref_cnt %d, sg %p",
cmnd, cmnd->scst_state, cmnd->data_waiting,
atomic_read(&cmnd->ref_cnt), cmnd->parent_req,
atomic_read(&cmnd->net_ref_cnt), cmnd->sg);
TRACE_CONN_CLOSE_DBG("cmd %p, scst_state %x, "
"r2t_len_to_receive %d, ref_cnt %d, parent_req %p, "
"net_ref_cnt %d, sg %p", cmnd, cmnd->scst_state,
cmnd->r2t_len_to_receive, atomic_read(&cmnd->ref_cnt),
cmnd->parent_req, atomic_read(&cmnd->net_ref_cnt),
cmnd->sg);
sBUG_ON(cmnd->parent_req != NULL);
@@ -113,7 +114,6 @@ again:
goto again;
}
spin_lock_bh(&cmnd->rsp_cmd_lock);
list_for_each_entry(rsp, &cmnd->rsp_cmd_list,
rsp_cmd_list_entry) {
TRACE_CONN_CLOSE_DBG(" rsp %p, ref_cnt %d, "
@@ -138,7 +138,6 @@ again:
if (page->net_priv != NULL) {
if (restart == 0) {
spin_unlock_bh(&cmnd->rsp_cmd_lock);
spin_unlock_bh(&conn->cmd_list_lock);
restart = 1;
}
@@ -152,7 +151,6 @@ again:
goto again;
}
}
spin_unlock_bh(&cmnd->rsp_cmd_lock);
}
spin_unlock_bh(&conn->cmd_list_lock);
@@ -191,7 +189,7 @@ static void free_pending_commands(struct iscsi_conn *conn)
spin_unlock(&session->sn_lock);
req_cmnd_release_force(cmnd, 0);
req_cmnd_release_force(cmnd);
req_freed = 1;
spin_lock(&session->sn_lock);
@@ -231,7 +229,7 @@ static void free_orphaned_pending_commands(struct iscsi_conn *conn)
spin_unlock(&session->sn_lock);
req_cmnd_release_force(cmnd, 0);
req_cmnd_release_force(cmnd);
req_freed = 1;
spin_lock(&session->sn_lock);
@@ -261,13 +259,13 @@ static void trace_conn_close(struct iscsi_conn *conn)
list_for_each_entry(cmnd, &conn->cmd_list,
cmd_list_entry) {
TRACE_CONN_CLOSE_DBG(
"cmd %p, scst_state %x, scst_cmd state %d, "
"data_waiting %d, ref_cnt %d, sn %u, "
"cmd %p, scst_cmd %p, scst_state %x, scst_cmd state "
"%d, r2t_len_to_receive %d, ref_cnt %d, sn %u, "
"parent_req %p, pending %d",
cmnd, cmnd->scst_state,
(cmnd->parent_req && cmnd->scst_cmd) ?
cmnd, cmnd->scst_cmd, cmnd->scst_state,
((cmnd->parent_req == NULL) && cmnd->scst_cmd) ?
cmnd->scst_cmd->state : -1,
cmnd->data_waiting, atomic_read(&cmnd->ref_cnt),
cmnd->r2t_len_to_receive, atomic_read(&cmnd->ref_cnt),
cmnd->pdu.bhs.sn, cmnd->parent_req, cmnd->pending);
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
TRACE_CONN_CLOSE_DBG("net_ref_cnt %d, sg %p",
@@ -286,7 +284,6 @@ static void trace_conn_close(struct iscsi_conn *conn)
sBUG_ON(cmnd->parent_req != NULL);
spin_lock_bh(&cmnd->rsp_cmd_lock);
list_for_each_entry(rsp, &cmnd->rsp_cmd_list,
rsp_cmd_list_entry) {
TRACE_CONN_CLOSE_DBG(" rsp %p, "
@@ -305,7 +302,6 @@ static void trace_conn_close(struct iscsi_conn *conn)
}
}
}
spin_unlock_bh(&cmnd->rsp_cmd_lock);
#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
}
spin_unlock_bh(&conn->cmd_list_lock);
@@ -433,21 +429,27 @@ static void close_conn(struct iscsi_conn *conn)
struct iscsi_cmnd *cmnd = conn->read_cmnd;
if (cmnd->scst_state == ISCSI_CMD_STATE_RX_CMD) {
TRACE_DBG("Going to wait for cmnd %p to change state "
"from RX_CMD", cmnd);
TRACE_CONN_CLOSE_DBG("Going to wait for cmnd %p to "
"change state from RX_CMD", cmnd);
}
wait_event(conn->read_state_waitQ,
cmnd->scst_state != ISCSI_CMD_STATE_RX_CMD);
TRACE_CONN_CLOSE_DBG("Releasing conn->read_cmnd %p (conn %p)",
conn->read_cmnd, conn);
conn->read_cmnd = NULL;
conn->read_state = RX_INIT_BHS;
req_cmnd_release_force(cmnd, 0);
req_cmnd_release_force(cmnd);
}
conn_abort(conn);
/* ToDo: not the best way to wait */
while (atomic_read(&conn->conn_ref_cnt) != 0) {
if (conn->conn_tm_active)
iscsi_check_tm_data_wait_timeouts(conn, true);
mutex_lock(&target->target_mutex);
spin_lock(&session->sn_lock);
if (session->tm_rsp && session->tm_rsp->conn == conn) {
@@ -637,6 +639,24 @@ static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn)
}
spin_unlock_bh(&conn->write_list_lock);
if (unlikely(test_bit(ISCSI_CMD_ABORTED,
&cmnd->parent_req->prelim_compl_flags))) {
TRACE_MGMT_DBG("Going to send acmd %p (scst cmd %p, "
"state %d, parent_req %p)", cmnd, cmnd->scst_cmd,
cmnd->scst_state, cmnd->parent_req);
}
if (unlikely(cmnd_opcode(cmnd) == ISCSI_OP_SCSI_TASK_MGT_RSP)) {
struct iscsi_task_mgt_hdr *req_hdr =
(struct iscsi_task_mgt_hdr *)&cmnd->parent_req->pdu.bhs;
struct iscsi_task_rsp_hdr *rsp_hdr =
(struct iscsi_task_rsp_hdr *)&cmnd->pdu.bhs;
TRACE_MGMT_DBG("Going to send TM response %p (status %d, "
"fn %d, parent_req %p)", cmnd, rsp_hdr->response,
req_hdr->function & ISCSI_FUNCTION_MASK,
cmnd->parent_req);
}
return cmnd;
}
@@ -702,8 +722,10 @@ restart:
TRACE_DBG("ERESTARTSYS received for conn %p", conn);
goto restart;
default:
PRINT_ERROR("sock_recvmsg() failed: %d", res);
mark_conn_closed(conn);
if (!conn->closing) {
PRINT_ERROR("sock_recvmsg() failed: %d", res);
mark_conn_closed(conn);
}
if (res == 0)
res = -EIO;
break;
@@ -970,9 +992,15 @@ static void scst_do_job_rd(void)
spin_lock_bh(&iscsi_rd_lock);
if (closed)
if (unlikely(closed))
continue;
if (unlikely(conn->conn_tm_active)) {
spin_unlock_bh(&iscsi_rd_lock);
iscsi_check_tm_data_wait_timeouts(conn, false);
spin_lock_bh(&iscsi_rd_lock);
}
#ifdef CONFIG_SCST_EXTRACHECKS
conn->rd_task = NULL;
#endif
@@ -1107,7 +1135,76 @@ static inline void __iscsi_get_page_callback(struct iscsi_cmnd *cmd) {}
static inline void __iscsi_put_page_callback(struct iscsi_cmnd *cmd) {}
#endif
/* This is partially taken from the Ardis code. */
void req_add_to_write_timeout_list(struct iscsi_cmnd *req)
{
struct iscsi_conn *conn;
unsigned long timeout_time;
bool set_conn_tm_active = false;
TRACE_ENTRY();
if (req->on_write_timeout_list)
goto out;
conn = req->conn;
TRACE_DBG("Adding req %p to conn %p write_timeout_list",
req, conn);
spin_lock_bh(&conn->write_list_lock);
req->on_write_timeout_list = 1;
req->write_start = jiffies;
list_add_tail(&req->write_timeout_list_entry,
&conn->write_timeout_list);
if (!timer_pending(&conn->rsp_timer)) {
if (unlikely(conn->conn_tm_active ||
test_bit(ISCSI_CMD_ABORTED,
&req->prelim_compl_flags))) {
set_conn_tm_active = true;
timeout_time = req->write_start +
ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT;
} else
timeout_time = req->write_start +
ISCSI_RSP_SCHED_TIMEOUT;
TRACE_DBG("Starting timer on %ld (con %p, write_start %ld)",
timeout_time, conn, req->write_start);
conn->rsp_timer.expires = timeout_time;
add_timer(&conn->rsp_timer);
} else if (unlikely(test_bit(ISCSI_CMD_ABORTED,
&req->prelim_compl_flags))) {
unsigned long timeout_time = jiffies +
ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT;
set_conn_tm_active = true;
if (time_after(conn->rsp_timer.expires, timeout_time)) {
TRACE_MGMT_DBG("Mod timer on %ld (conn %p)",
timeout_time, conn);
mod_timer(&conn->rsp_timer, timeout_time);
}
}
spin_unlock_bh(&conn->write_list_lock);
/*
* conn_tm_active can be already cleared by
* iscsi_check_tm_data_wait_timeouts(). write_list_lock is an inner
* lock for iscsi_rd_lock.
*/
if (unlikely(set_conn_tm_active)) {
spin_lock_bh(&iscsi_rd_lock);
TRACE_MGMT_DBG("Setting conn_tm_active for conn %p", conn);
conn->conn_tm_active = 1;
spin_unlock_bh(&iscsi_rd_lock);
}
out:
TRACE_EXIT();
return;
}
static int write_data(struct iscsi_conn *conn)
{
mm_segment_t oldfs;
@@ -1130,7 +1227,7 @@ static int write_data(struct iscsi_conn *conn)
iscsi_extracheck_is_wr_thread(conn);
if (write_cmnd->own_sg == 0) {
if (!write_cmnd->own_sg) {
ref_cmd = write_cmnd->parent_req;
ref_cmd_to_parent = true;
} else {
@@ -1138,28 +1235,7 @@ static int write_data(struct iscsi_conn *conn)
ref_cmd_to_parent = false;
}
if (!ref_cmd->on_written_list) {
TRACE_DBG("Adding cmd %p to conn %p written_list", ref_cmd,
conn);
spin_lock_bh(&conn->write_list_lock);
ref_cmd->on_written_list = 1;
ref_cmd->write_timeout = jiffies + ISCSI_RSP_TIMEOUT;
list_add_tail(&ref_cmd->written_list_entry,
&conn->written_list);
spin_unlock_bh(&conn->write_list_lock);
}
if (!timer_pending(&conn->rsp_timer)) {
sBUG_ON(!ref_cmd->on_written_list);
spin_lock_bh(&conn->write_list_lock);
if (likely(!timer_pending(&conn->rsp_timer))) {
TRACE_DBG("Starting timer on %ld (conn %p)",
ref_cmd->write_timeout, conn);
conn->rsp_timer.expires = ref_cmd->write_timeout;
add_timer(&conn->rsp_timer);
}
spin_unlock_bh(&conn->write_list_lock);
}
req_add_to_write_timeout_list(write_cmnd->parent_req);
file = conn->file;
size = conn->write_size;

View File

@@ -91,9 +91,9 @@ static int iscsi_session_alloc(struct iscsi_target *target,
spin_lock_init(&session->sn_lock);
spin_lock_init(&session->cmnd_hash_lock);
for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++)
INIT_LIST_HEAD(&session->cmnd_hash[i]);
spin_lock_init(&session->cmnd_data_wait_hash_lock);
for (i = 0; i < ARRAY_SIZE(session->cmnd_data_wait_hash); i++)
INIT_LIST_HEAD(&session->cmnd_data_wait_hash[i]);
session->next_ttt = 1;
@@ -274,8 +274,8 @@ int session_free(struct iscsi_session *session, bool del)
sBUG();
}
for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++)
sBUG_ON(!list_empty(&session->cmnd_hash[i]));
for (i = 0; i < ARRAY_SIZE(session->cmnd_data_wait_hash); i++)
sBUG_ON(!list_empty(&session->cmnd_data_wait_hash[i]));
if (session->sess_reinst_successor != NULL)
sess_reinst_finished(session->sess_reinst_successor);

View File

@@ -302,9 +302,9 @@ struct iscsi_key session_keys[] = {
{"MaxXmitDataSegmentLength", 8192, -1, 512, -1, &minimum_ops},
{"MaxBurstLength", 262144, -1, 512, -1, &minimum_ops},
{"FirstBurstLength", 65536, -1, 512, -1, &minimum_ops},
{"DefaultTime2Wait", 2, 2, 0, 3600, &maximum_ops},
{"DefaultTime2Retain", 20, 20, 0, 3600, &minimum_ops},
{"MaxOutstandingR2T", 1, 20, 1, 65535, &minimum_ops},
{"DefaultTime2Wait", 2, 0, 0, 3600, &maximum_ops},
{"DefaultTime2Retain", 20, 0, 0, 3600, &minimum_ops},
{"MaxOutstandingR2T", 1, 32, 1, 65535, &minimum_ops},
{"DataPDUInOrder", 1, 0, 0, 1, &or_ops},
{"DataSequenceInOrder", 1, 0, 0, 1, &or_ops},
{"ErrorRecoveryLevel", 0, 0, 0, 0, &minimum_ops},

View File

@@ -115,41 +115,44 @@ static inline int list_is_last(const struct list_head *list,
/* Allocation of the cmd's data buffer */
#define SCST_CMD_STATE_PREPARE_SPACE 2
/* Calling preprocessing_done() */
#define SCST_CMD_STATE_PREPROCESSING_DONE 3
/* Target driver's rdy_to_xfer() is going to be called */
#define SCST_CMD_STATE_RDY_TO_XFER 3
#define SCST_CMD_STATE_RDY_TO_XFER 4
/* Target driver's pre_exec() is going to be called */
#define SCST_CMD_STATE_TGT_PRE_EXEC 4
#define SCST_CMD_STATE_TGT_PRE_EXEC 5
/* Cmd is going to be sent for execution */
#define SCST_CMD_STATE_SEND_FOR_EXEC 5
#define SCST_CMD_STATE_SEND_FOR_EXEC 6
/* Cmd is being checked if it should be executed locally */
#define SCST_CMD_STATE_LOCAL_EXEC 6
#define SCST_CMD_STATE_LOCAL_EXEC 7
/* Cmd is ready for execution */
#define SCST_CMD_STATE_REAL_EXEC 7
#define SCST_CMD_STATE_REAL_EXEC 8
/* Internal post-exec checks */
#define SCST_CMD_STATE_PRE_DEV_DONE 8
#define SCST_CMD_STATE_PRE_DEV_DONE 9
/* Internal MODE SELECT pages related checks */
#define SCST_CMD_STATE_MODE_SELECT_CHECKS 9
#define SCST_CMD_STATE_MODE_SELECT_CHECKS 10
/* Dev handler's dev_done() is going to be called */
#define SCST_CMD_STATE_DEV_DONE 10
#define SCST_CMD_STATE_DEV_DONE 11
/* Target driver's xmit_response() is going to be called */
#define SCST_CMD_STATE_PRE_XMIT_RESP 11
#define SCST_CMD_STATE_PRE_XMIT_RESP 12
/* Target driver's xmit_response() is going to be called */
#define SCST_CMD_STATE_XMIT_RESP 12
#define SCST_CMD_STATE_XMIT_RESP 13
/* Cmd finished */
#define SCST_CMD_STATE_FINISHED 13
#define SCST_CMD_STATE_FINISHED 14
/* Internal cmd finished */
#define SCST_CMD_STATE_FINISHED_INTERNAL 14
#define SCST_CMD_STATE_FINISHED_INTERNAL 15
#define SCST_CMD_STATE_LAST_ACTIVE (SCST_CMD_STATE_FINISHED_INTERNAL+100)
@@ -159,8 +162,8 @@ static inline int list_is_last(const struct list_head *list,
/* LUN translation (cmd->tgt_dev assignment) */
#define SCST_CMD_STATE_INIT (SCST_CMD_STATE_LAST_ACTIVE+2)
/* Allocation of the cmd's data buffer */
#define SCST_CMD_STATE_PREPROCESS_DONE (SCST_CMD_STATE_LAST_ACTIVE+3)
/* Waiting for scst_restart_cmd() */
#define SCST_CMD_STATE_PREPROCESSING_DONE_CALLED (SCST_CMD_STATE_LAST_ACTIVE+3)
/* Waiting for data from the initiator (until scst_rx_data() called) */
#define SCST_CMD_STATE_DATA_WAIT (SCST_CMD_STATE_LAST_ACTIVE+4)
@@ -704,6 +707,8 @@ struct scst_tgt_template {
* A target driver could need to do some actions at this stage.
* After the target driver done the needed actions, it shall call
* scst_restart_cmd() in order to continue processing this command.
* In case of preliminary the command completion, this function will
* also be called before xmit_response().
*
* Called only if the cmd is queued using scst_cmd_init_stage1_done()
* instead of scst_cmd_init_done().
@@ -1212,19 +1217,15 @@ struct scst_session {
struct list_head sess_tgt_dev_list_hash[TGT_DEV_HASH_SIZE];
/*
* List of cmds in this session. Used to find a cmd in the
* session. Protected by sess_list_lock.
* List of cmds in this session. Protected by sess_list_lock.
*
* We must always keep commands in the sess list from the
* very beginning, because otherwise they can be missed during
* TM processing.
*/
struct list_head search_cmd_list;
struct list_head sess_cmd_list;
spinlock_t sess_list_lock; /* protects search_cmd_list, etc */
/*
* List of cmds in this in the state after PRE_XMIT_RESP. All the cmds
* moved here from search_cmd_list. Needed for hw_pending_work.
* Protected by sess_list_lock.
*/
struct list_head after_pre_xmit_cmd_list;
spinlock_t sess_list_lock; /* protects sess_cmd_list, etc */
atomic_t refcnt; /* get/put counter */
@@ -1484,7 +1485,7 @@ struct scst_cmd {
/* The corresponding sn_slot in tgt_dev->sn_slots */
atomic_t *sn_slot;
/* List entry for sess's search_cmd_list and after_pre_xmit_cmd_list */
/* List entry for sess's sess_cmd_list */
struct list_head sess_cmd_list_entry;
/*
@@ -2326,14 +2327,18 @@ static inline int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn,
int scst_get_cdb_info(struct scst_cmd *cmd);
/*
* Set error SCSI status in the command and prepares it for returning it
* Set error SCSI status in the command and prepares it for returning it.
*
* Returns 0 on success, error code otherwise.
*/
void scst_set_cmd_error_status(struct scst_cmd *cmd, int status);
int scst_set_cmd_error_status(struct scst_cmd *cmd, int status);
/*
* Set error in the command and fill the sense buffer
* Set error in the command and fill the sense buffer.
*
* Returns 0 on success, error code otherwise.
*/
void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq);
int scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq);
/*
* Sets BUSY or TASK QUEUE FULL status
@@ -2490,6 +2495,14 @@ static inline int scst_cmd_atomic(struct scst_cmd *cmd)
return res;
}
/*
* Returns TRUE if cmd has been completed.
*/
static inline int scst_cmd_completed(struct scst_cmd *cmd)
{
return cmd->completed;
}
static inline enum scst_exec_context __scst_estimate_context(bool direct)
{
if (in_irq())

View File

@@ -98,6 +98,7 @@
#define TRACE_MGMT_DEBUG 0x00001000
#define TRACE_SCSI 0x00002000
#define TRACE_SPECIAL 0x00004000 /* filtering debug, etc */
#define TRACE_FLOW_CONTROL 0x00008000 /* flow control in action */
#define TRACE_ALL 0xffffffff
/* Flags 0xXXXX0000 are local for users */
@@ -308,11 +309,13 @@ do { \
#define TRACE_MEM(format, args...) do {} while (0)
#define TRACE_SG(format, args...) do {} while (0)
#define TRACE_DBG(format, args...) do {} while (0)
#define TRACE_DBG_FLAG(format, args...) do {} while (0)
#define TRACE_DBG_SPECIAL(format, args...) do {} while (0)
#define TRACE_MGMT_DBG(format, args...) do {} while (0)
#define TRACE_MGMT_DBG_SPECIAL(format, args...) do {} while (0)
#define TRACE_BUFFER(message, buff, len) do {} while (0)
#define TRACE_BUFF_FLAG(flag, message, buff, len) do {} while (0)
#ifndef GENERATING_UPSTREAM_PATCH
#define TRACE_ENTRY() do {} while (0)
#define TRACE_EXIT() do {} while (0)

View File

@@ -554,7 +554,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_cdb_len_10}
};
#define SCST_CDB_TBL_SIZE ARRAY_SIZE(scst_scsi_op_table)
#define SCST_CDB_TBL_SIZE ((int)ARRAY_SIZE(scst_scsi_op_table))
static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev);
static void scst_check_internal_sense(struct scst_device *dev, int result,
@@ -620,6 +620,11 @@ int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic,
TRACE_ENTRY();
/*
* We don't check here if the existing sense is valid or not, because
* we suppose the caller did it based on cmd->status.
*/
res = scst_alloc_sense(cmd, atomic);
if (res != 0) {
PRINT_BUFFER("Lost sense", sense, len);
@@ -642,10 +647,19 @@ out:
}
EXPORT_SYMBOL(scst_alloc_set_sense);
void scst_set_cmd_error_status(struct scst_cmd *cmd, int status)
int scst_set_cmd_error_status(struct scst_cmd *cmd, int status)
{
int res = 0;
TRACE_ENTRY();
if (cmd->status != 0) {
TRACE_MGMT_DBG("cmd %p already has status %x set", cmd,
cmd->status);
res = -EEXIST;
goto out;
}
cmd->status = status;
cmd->host_status = DID_OK;
@@ -658,21 +672,24 @@ void scst_set_cmd_error_status(struct scst_cmd *cmd, int status)
cmd->completed = 1;
TRACE_EXIT();
return;
out:
TRACE_EXIT_RES(res);
return res;
}
EXPORT_SYMBOL(scst_set_cmd_error_status);
void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq)
int scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq)
{
int rc;
int res;
TRACE_ENTRY();
scst_set_cmd_error_status(cmd, SAM_STAT_CHECK_CONDITION);
res = scst_set_cmd_error_status(cmd, SAM_STAT_CHECK_CONDITION);
if (res != 0)
goto out;
rc = scst_alloc_sense(cmd, 1);
if (rc != 0) {
res = scst_alloc_sense(cmd, 1);
if (res != 0) {
PRINT_ERROR("Lost sense data (key %x, asc %x, ascq %x)",
key, asc, ascq);
goto out;
@@ -683,8 +700,8 @@ void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq)
TRACE_BUFFER("Sense set", cmd->sense, cmd->sense_valid_len);
out:
TRACE_EXIT();
return;
TRACE_EXIT_RES(res);
return res;
}
EXPORT_SYMBOL(scst_set_cmd_error);
@@ -871,16 +888,22 @@ out:
}
EXPORT_SYMBOL(scst_check_convert_sense);
static void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
static int scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
unsigned int len)
{
int res;
TRACE_ENTRY();
scst_set_cmd_error_status(cmd, SAM_STAT_CHECK_CONDITION);
scst_alloc_set_sense(cmd, 1, sense, len);
res = scst_set_cmd_error_status(cmd, SAM_STAT_CHECK_CONDITION);
if (res != 0)
goto out;
TRACE_EXIT();
return;
res = scst_alloc_set_sense(cmd, 1, sense, len);
out:
TRACE_EXIT_RES(res);
return res;
}
void scst_set_busy(struct scst_cmd *cmd)
@@ -891,13 +914,13 @@ void scst_set_busy(struct scst_cmd *cmd)
if ((c <= 1) || (cmd->sess->init_phase != SCST_SESS_IPH_READY)) {
scst_set_cmd_error_status(cmd, SAM_STAT_BUSY);
TRACE(TRACE_MGMT_MINOR, "Sending BUSY status to initiator %s "
TRACE(TRACE_FLOW_CONTROL, "Sending BUSY status to initiator %s "
"(cmds count %d, queue_type %x, sess->init_phase %d)",
cmd->sess->initiator_name, c,
cmd->queue_type, cmd->sess->init_phase);
} else {
scst_set_cmd_error_status(cmd, SAM_STAT_TASK_SET_FULL);
TRACE(TRACE_MGMT_MINOR, "Sending QUEUE_FULL status to "
TRACE(TRACE_FLOW_CONTROL, "Sending QUEUE_FULL status to "
"initiator %s (cmds count %d, queue_type %x, "
"sess->init_phase %d)", cmd->sess->initiator_name, c,
cmd->queue_type, cmd->sess->init_phase);
@@ -996,7 +1019,7 @@ static void scst_free_aen(struct scst_aen *aen)
return;
};
/* Must be called unded scst_mutex */
/* Must be called under scst_mutex */
void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev,
int key, int asc, int ascq)
{
@@ -1473,6 +1496,10 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
case SCST_CMD_STATE_INIT:
case SCST_CMD_STATE_PRE_PARSE:
case SCST_CMD_STATE_DEV_PARSE:
if (cmd->preprocessing_only) {
res = SCST_CMD_STATE_PREPROCESSING_DONE;
break;
} /* else go through */
case SCST_CMD_STATE_DEV_DONE:
if (cmd->internal)
res = SCST_CMD_STATE_FINISHED_INTERNAL;
@@ -1489,8 +1516,19 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
res = SCST_CMD_STATE_XMIT_RESP;
break;
case SCST_CMD_STATE_PREPROCESS_DONE:
case SCST_CMD_STATE_PREPROCESSING_DONE:
case SCST_CMD_STATE_PREPROCESSING_DONE_CALLED:
if (cmd->tgt_dev == NULL)
res = SCST_CMD_STATE_PRE_XMIT_RESP;
else
res = SCST_CMD_STATE_PRE_DEV_DONE;
break;
case SCST_CMD_STATE_PREPARE_SPACE:
if (cmd->preprocessing_only) {
res = SCST_CMD_STATE_PREPROCESSING_DONE;
break;
} /* else go through */
case SCST_CMD_STATE_RDY_TO_XFER:
case SCST_CMD_STATE_DATA_WAIT:
case SCST_CMD_STATE_TGT_PRE_EXEC:
@@ -1533,7 +1571,8 @@ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd)
cmd->state = scst_get_cmd_abnormal_done_state(cmd);
#ifdef CONFIG_SCST_EXTRACHECKS
if ((cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
if (((cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
(cmd->state != SCST_CMD_STATE_PREPROCESSING_DONE)) &&
(cmd->tgt_dev == NULL) && !cmd->internal) {
PRINT_CRIT_ERROR("Wrong not inited cmd state %d (cmd %p, "
"op %x)", cmd->state, cmd, cmd->cdb[0]);
@@ -1706,8 +1745,7 @@ static void scst_hw_pending_work_fn(struct delayed_work *work)
spin_lock_irqsave(&sess->sess_list_lock, flags);
restart:
list_for_each_entry(cmd, &sess->search_cmd_list,
sess_cmd_list_entry) {
list_for_each_entry(cmd, &sess->sess_cmd_list, sess_cmd_list_entry) {
int rc;
rc = scst_check_hw_pending_cmd(cmd, cur_time, max_time, sess,
@@ -1720,23 +1758,7 @@ restart:
goto restart;
}
restart1:
list_for_each_entry(cmd, &sess->after_pre_xmit_cmd_list,
sess_cmd_list_entry) {
int rc;
rc = scst_check_hw_pending_cmd(cmd, cur_time, max_time, sess,
&flags, tgtt);
if (rc < 0)
break;
else if (rc == 0)
continue;
else
goto restart1;
}
if (!list_empty(&sess->search_cmd_list) ||
!list_empty(&sess->after_pre_xmit_cmd_list)) {
if (list_empty(&sess->sess_cmd_list)) {
/*
* For stuck cmds if there is no activity we might need to have
* one more run to release them, so reschedule once again.
@@ -2438,7 +2460,7 @@ int scst_acg_add_name(struct scst_acg *acg, const char *name)
if (strcmp(n->name, name) == 0) {
PRINT_ERROR("Name %s already exists in group %s",
name, acg->acg_name);
res = -EINVAL;
res = -EEXIST;
goto out;
}
}
@@ -2834,8 +2856,7 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, gfp_t gfp_mask,
INIT_LIST_HEAD(sess_tgt_dev_list_head);
}
spin_lock_init(&sess->sess_list_lock);
INIT_LIST_HEAD(&sess->search_cmd_list);
INIT_LIST_HEAD(&sess->after_pre_xmit_cmd_list);
INIT_LIST_HEAD(&sess->sess_cmd_list);
sess->tgt = tgt;
INIT_LIST_HEAD(&sess->init_deferred_cmd_list);
INIT_LIST_HEAD(&sess->init_deferred_mcmd_list);
@@ -3867,7 +3888,7 @@ int scst_get_cdb_info(struct scst_cmd *cmd)
op = cmd->cdb[0]; /* get clear opcode */
TRACE_DBG("opcode=%02x, cdblen=%d bytes, tblsize=%zd, "
TRACE_DBG("opcode=%02x, cdblen=%d bytes, tblsize=%d, "
"dev_type=%d", op, SCST_GET_CDB_LEN(op), SCST_CDB_TBL_SIZE,
dev_type);
@@ -4676,9 +4697,9 @@ void scst_process_reset(struct scst_device *dev,
spin_lock_irq(&sess->sess_list_lock);
TRACE_DBG("Searching in search cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->search_cmd_list,
sess_cmd_list_entry) {
TRACE_DBG("Searching in sess cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->sess_cmd_list,
sess_cmd_list_entry) {
if (cmd == exclude_cmd)
continue;
if ((cmd->tgt_dev == tgt_dev) ||
@@ -4736,7 +4757,7 @@ again:
TRACE_DBG("%s",
"SCST_TGT_DEV_UA_PENDING set, but UA_list empty");
res = -1;
goto out_unlock;
goto out_unlock_tgt_dev_lock;
}
UA_entry = list_entry(cmd->tgt_dev->UA_list.next, typeof(*UA_entry),
@@ -4774,8 +4795,9 @@ again:
goto again;
}
scst_set_cmd_error_sense(cmd, UA_entry->UA_sense_buffer,
UA_entry->UA_valid_sense_len);
if (scst_set_cmd_error_sense(cmd, UA_entry->UA_sense_buffer,
UA_entry->UA_valid_sense_len) != 0)
goto out_unlock;
cmd->ua_ignore = 1;
@@ -4831,6 +4853,7 @@ out_unlock:
spin_lock_bh(&cmd->tgt_dev->tgt_dev_lock);
}
out_unlock_tgt_dev_lock:
spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock);
TRACE_EXIT_RES(res);
@@ -5600,7 +5623,6 @@ static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
if (tm_dbg_tgt_dev != NULL)
tm_dbg_deinit_tgt_dev(tm_dbg_tgt_dev);
/* Do TM debugging only for LUN 0 */
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
tm_dbg_state = INIT_TM_DBG_STATE;
tm_dbg_on_state_passes =

View File

@@ -110,6 +110,7 @@ static struct scst_trace_log scst_proc_trace_tbl[] = {
{ TRACE_MGMT, "mgmt" },
{ TRACE_MGMT_MINOR, "mgmt_minor" },
{ TRACE_MGMT_DEBUG, "mgmt_dbg" },
{ TRACE_FLOW_CONTROL, "flow_control" },
{ 0, NULL }
};
@@ -1975,7 +1976,7 @@ static ssize_t scst_proc_groups_devices_write(struct file *file,
if (action == SCST_PROC_ACTION_ADD) {
PRINT_ERROR("virt lun %d already exists in "
"group %s", virt_lun, acg->acg_name);
res = -EINVAL;
res = -EEXIST;
goto out_free_up;
} else {
/* Replace */
@@ -2324,15 +2325,26 @@ static int scst_sessions_info_show(struct seq_file *seq, void *v)
seq_printf(seq, "%-20s %-45s %-35s %-15s\n",
"Target name", "Initiator name",
"Group name", "Command Count");
"Group name", "Active/All Commands Count");
list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
list_for_each_entry(sess, &acg->acg_sess_list,
acg_sess_list_entry) {
seq_printf(seq, "%-20s %-45s %-35s %-15d\n",
acg_sess_list_entry) {
int active_cmds = 0, t;
for (t = TGT_DEV_HASH_SIZE-1; t >= 0; t--) {
struct list_head *sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[t];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev,
sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
active_cmds += atomic_read(&tgt_dev->tgt_dev_cmd_count);
}
}
seq_printf(seq, "%-20s %-45s %-35s %d/%d\n",
sess->tgt->tgtt->name,
sess->initiator_name,
acg->acg_name,
acg->acg_name, active_cmds,
atomic_read(&sess->sess_cmd_count));
}
}

View File

@@ -81,6 +81,7 @@ static struct scst_trace_log scst_trace_tbl[] = {
{ TRACE_MGMT, "mgmt" },
{ TRACE_MGMT_MINOR, "mgmt_minor" },
{ TRACE_MGMT_DEBUG, "mgmt_dbg" },
{ TRACE_FLOW_CONTROL, "flow_control" },
{ 0, NULL }
};
@@ -770,7 +771,7 @@ void scst_device_sysfs_put(struct scst_device *dev)
* Target sessions directory implementation
*/
ssize_t scst_sess_sysfs_commands_show(struct kobject *kobj,
static ssize_t scst_sess_sysfs_commands_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct scst_session *sess;
@@ -783,7 +784,42 @@ ssize_t scst_sess_sysfs_commands_show(struct kobject *kobj,
static struct kobj_attribute session_commands_attr =
__ATTR(commands, S_IRUGO, scst_sess_sysfs_commands_show, NULL);
ssize_t scst_sess_sysfs_initiator_name_show(struct kobject *kobj,
static ssize_t scst_sess_sysfs_active_commands_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int res;
struct scst_session *sess;
int active_cmds = 0, t;
if (mutex_lock_interruptible(&scst_mutex) != 0) {
res = -EINTR;
goto out;
}
sess = container_of(kobj, struct scst_session, sess_kobj);
for (t = TGT_DEV_HASH_SIZE-1; t >= 0; t--) {
struct list_head *sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[t];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
active_cmds += atomic_read(&tgt_dev->tgt_dev_cmd_count);
}
}
mutex_unlock(&scst_mutex);
res = sprintf(buf, "%i\n", active_cmds);
out:
return res;
}
static struct kobj_attribute session_active_commands_attr =
__ATTR(commands, S_IRUGO, scst_sess_sysfs_active_commands_show, NULL);
static ssize_t scst_sess_sysfs_initiator_name_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct scst_session *sess;
@@ -799,6 +835,7 @@ static struct kobj_attribute session_initiator_name_attr =
static struct attribute *scst_session_attrs[] = {
&session_commands_attr.attr,
&session_active_commands_attr.attr,
&session_initiator_name_attr.attr,
NULL,
};
@@ -1241,7 +1278,7 @@ static ssize_t scst_luns_mgmt_store(struct kobject *kobj,
if (action == SCST_LUN_ACTION_ADD) {
PRINT_ERROR("virt lun %d already exists in "
"group %s", virt_lun, acg->acg_name);
res = -EINVAL;
res = -EEXIST;
goto out_free_up;
} else {
/* Replace */

View File

@@ -164,6 +164,8 @@ out_redirect:
/*
* Poor man solution for single threaded targets, where
* blocking receiver at least sometimes means blocking all.
* For instance, iSCSI target won't be able to receive
* Data-Out PDUs.
*/
sBUG_ON(*context != SCST_CONTEXT_DIRECT);
scst_set_busy(cmd);
@@ -222,14 +224,14 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
if (unlikely(sess->init_phase != SCST_SESS_IPH_READY)) {
/*
* We have to always keep command in the search list from the
* very beginning, because otherwise it can be missed during
* We must always keep commands in the sess list from the
* very beginning, because otherwise they can be missed during
* TM processing. This check is needed because there might be
* old, i.e. deferred, commands and new, i.e. just coming, ones.
*/
if (cmd->sess_cmd_list_entry.next == NULL)
list_add_tail(&cmd->sess_cmd_list_entry,
&sess->search_cmd_list);
&sess->sess_cmd_list);
switch (sess->init_phase) {
case SCST_SESS_IPH_SUCCESS:
break;
@@ -250,7 +252,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
}
} else
list_add_tail(&cmd->sess_cmd_list_entry,
&sess->search_cmd_list);
&sess->sess_cmd_list);
spin_unlock_irqrestore(&sess->sess_list_lock, flags);
@@ -287,12 +289,6 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
rc = scst_init_cmd(cmd, &pref_context);
if (unlikely(rc < 0))
goto out;
else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION)) {
if (rc == 0) {
/* Target driver preliminary completed cmd */
scst_set_cmd_abnormal_done_state(cmd);
}
}
active:
/* Here cmd must not be in any cmd list, no locks */
@@ -303,12 +299,10 @@ active:
case SCST_CONTEXT_DIRECT:
scst_process_active_cmd(cmd, false);
/* For *NEED_THREAD wake_up() is already done */
break;
case SCST_CONTEXT_DIRECT_ATOMIC:
scst_process_active_cmd(cmd, true);
/* For *NEED_THREAD wake_up() is already done */
break;
default:
@@ -639,6 +633,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
}
set_res:
#ifdef CONFIG_SCST_EXTRACHECKS
switch (state) {
case SCST_CMD_STATE_PREPARE_SPACE:
case SCST_CMD_STATE_PRE_PARSE:
@@ -654,8 +649,10 @@ set_res:
case SCST_CMD_STATE_XMIT_RESP:
case SCST_CMD_STATE_FINISHED:
case SCST_CMD_STATE_FINISHED_INTERNAL:
#endif
cmd->state = state;
res = SCST_CMD_STATE_RES_CONT_SAME;
#ifdef CONFIG_SCST_EXTRACHECKS
break;
default:
@@ -670,6 +667,7 @@ set_res:
}
goto out_error;
}
#endif
if (cmd->resp_data_len == -1) {
if (cmd->data_direction & SCST_DATA_READ)
@@ -701,7 +699,7 @@ static int scst_prepare_space(struct scst_cmd *cmd)
TRACE_ENTRY();
if (cmd->data_direction == SCST_DATA_NONE)
goto prep_done;
goto done;
if (cmd->tgt_need_alloc_data_buf) {
int orig_bufflen = cmd->bufflen;
@@ -767,30 +765,10 @@ check:
goto out_no_space;
}
prep_done:
if (cmd->preprocessing_only) {
cmd->preprocessing_only = 0;
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("ABORTED set, returning ABORTED for "
"cmd %p", cmd);
scst_set_cmd_abnormal_done_state(cmd);
res = SCST_CMD_STATE_RES_CONT_SAME;
goto out;
}
res = SCST_CMD_STATE_RES_CONT_NEXT;
cmd->state = SCST_CMD_STATE_PREPROCESS_DONE;
TRACE_DBG("Calling preprocessing_done(cmd %p)", cmd);
scst_set_cur_start(cmd);
cmd->tgtt->preprocessing_done(cmd);
TRACE_DBG("%s", "preprocessing_done() returned");
goto out;
}
if (cmd->data_direction & SCST_DATA_WRITE)
done:
if (cmd->preprocessing_only)
cmd->state = SCST_CMD_STATE_PREPROCESSING_DONE;
else if (cmd->data_direction & SCST_DATA_WRITE)
cmd->state = SCST_CMD_STATE_RDY_TO_XFER;
else
cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
@@ -814,6 +792,28 @@ out_error:
goto out;
}
static int scst_preprocessing_done(struct scst_cmd *cmd)
{
int res;
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(!cmd->preprocessing_only);
cmd->preprocessing_only = 0;
res = SCST_CMD_STATE_RES_CONT_NEXT;
cmd->state = SCST_CMD_STATE_PREPROCESSING_DONE_CALLED;
TRACE_DBG("Calling preprocessing_done(cmd %p)", cmd);
scst_set_cur_start(cmd);
cmd->tgtt->preprocessing_done(cmd);
TRACE_DBG("%s", "preprocessing_done() returned");
TRACE_EXIT_HRES(res);
return res;
}
void scst_restart_cmd(struct scst_cmd *cmd, int status,
enum scst_exec_context pref_context)
{
@@ -2777,6 +2777,7 @@ static int scst_dev_done(struct scst_cmd *cmd)
}
switch (state) {
#ifdef CONFIG_SCST_EXTRACHECKS
case SCST_CMD_STATE_PRE_XMIT_RESP:
case SCST_CMD_STATE_DEV_PARSE:
case SCST_CMD_STATE_PRE_PARSE:
@@ -2792,16 +2793,18 @@ static int scst_dev_done(struct scst_cmd *cmd)
case SCST_CMD_STATE_XMIT_RESP:
case SCST_CMD_STATE_FINISHED:
case SCST_CMD_STATE_FINISHED_INTERNAL:
#else
default:
#endif
cmd->state = state;
break;
case SCST_CMD_STATE_NEED_THREAD_CTX:
TRACE_DBG("Dev handler %s dev_done() requested "
"thread context, rescheduling",
dev->handler->name);
res = SCST_CMD_STATE_RES_NEED_THREAD;
break;
#ifdef CONFIG_SCST_EXTRACHECKS
default:
if (state >= 0) {
PRINT_ERROR("Dev handler %s dev_done() returned "
@@ -2816,6 +2819,7 @@ static int scst_dev_done(struct scst_cmd *cmd)
SCST_LOAD_SENSE(scst_sense_hardw_error));
scst_set_cmd_abnormal_done_state(cmd);
break;
#endif
}
if (cmd->needs_unblocking)
@@ -2838,7 +2842,6 @@ out:
static int scst_pre_xmit_response(struct scst_cmd *cmd)
{
int res;
struct scst_session *sess = cmd->sess;
TRACE_ENTRY();
@@ -2860,6 +2863,10 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
#endif
if (likely(cmd->tgt_dev != NULL)) {
/*
* Those counters protect from not getting too long processing
* latency, so we should decrement them after cmd completed.
*/
atomic_dec(&cmd->tgt_dev->tgt_dev_cmd_count);
atomic_dec(&cmd->dev->dev_cmd_count);
#ifdef CONFIG_SCST_ORDERED_READS
@@ -2879,18 +2886,6 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
}
}
/*
* If we don't remove cmd from the search list here, before
* submitting it for transmittion, we will have a race, when for
* some reason cmd's release is delayed after transmittion and
* initiator sends cmd with the same tag => it is possible that
* a wrong cmd will be found by find() functions.
*/
spin_lock_irq(&sess->sess_list_lock);
list_move_tail(&cmd->sess_cmd_list_entry,
&sess->after_pre_xmit_cmd_list);
spin_unlock_irq(&sess->sess_list_lock);
cmd->done = 1;
smp_mb(); /* to sync with scst_abort_cmd() */
@@ -3318,7 +3313,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count);
if (unlikely(cnt > SCST_MAX_TGT_DEV_COMMANDS)) {
TRACE(TRACE_MGMT_MINOR,
TRACE(TRACE_FLOW_CONTROL,
"Too many pending commands (%d) in "
"session, returning BUSY to initiator \"%s\"",
cnt, (cmd->sess->initiator_name[0] == '\0') ?
@@ -3329,7 +3324,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
cnt = atomic_inc_return(&cmd->dev->dev_cmd_count);
if (unlikely(cnt > SCST_MAX_DEV_COMMANDS)) {
if (!failure) {
TRACE(TRACE_MGMT_MINOR,
TRACE(TRACE_FLOW_CONTROL,
"Too many pending device "
"commands (%d), returning BUSY to "
"initiator \"%s\"", cnt,
@@ -3538,6 +3533,10 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
res = scst_prepare_space(cmd);
break;
case SCST_CMD_STATE_PREPROCESSING_DONE:
res = scst_preprocessing_done(cmd);
break;
case SCST_CMD_STATE_RDY_TO_XFER:
res = scst_rdy_to_xfer(cmd);
break;
@@ -3624,8 +3623,8 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
/* None */
} else if (res == SCST_CMD_STATE_RES_NEED_THREAD) {
spin_lock_irq(&cmd->cmd_lists->cmd_list_lock);
#ifdef CONFIG_SCST_EXTRACHECKS
switch (cmd->state) {
case SCST_CMD_STATE_PRE_PARSE:
case SCST_CMD_STATE_DEV_PARSE:
case SCST_CMD_STATE_PREPARE_SPACE:
case SCST_CMD_STATE_RDY_TO_XFER:
@@ -3633,32 +3632,24 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
case SCST_CMD_STATE_SEND_FOR_EXEC:
case SCST_CMD_STATE_LOCAL_EXEC:
case SCST_CMD_STATE_REAL_EXEC:
case SCST_CMD_STATE_PRE_DEV_DONE:
case SCST_CMD_STATE_MODE_SELECT_CHECKS:
case SCST_CMD_STATE_DEV_DONE:
case SCST_CMD_STATE_PRE_XMIT_RESP:
case SCST_CMD_STATE_XMIT_RESP:
case SCST_CMD_STATE_FINISHED:
case SCST_CMD_STATE_FINISHED_INTERNAL:
#endif
TRACE_DBG("Adding cmd %p to head of active cmd list",
cmd);
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
break;
#ifdef CONFIG_SCST_EXTRACHECKS
/* not very valid commands */
case SCST_CMD_STATE_DEFAULT:
case SCST_CMD_STATE_NEED_THREAD_CTX:
break;
default:
PRINT_CRIT_ERROR("cmd %p is in invalid state %d)", cmd,
cmd->state);
spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock);
sBUG();
spin_lock_irq(&cmd->cmd_lists->cmd_list_lock);
break;
#endif
default:
break;
}
#endif
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock);
} else
@@ -4097,7 +4088,7 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
/*
* cmd can't die here or sess_list_lock already taken and
* cmd is in the search list
* cmd is in the sess list
*/
list_add_tail(&mstb->cmd_mgmt_cmd_list_entry,
&cmd->mgmt_cmd_list);
@@ -4250,8 +4241,8 @@ static void __scst_abort_task_set(struct scst_mgmt_cmd *mcmd,
spin_lock_irq(&sess->sess_list_lock);
TRACE_DBG("Searching in search cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->search_cmd_list,
TRACE_DBG("Searching in sess cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->sess_cmd_list,
sess_cmd_list_entry) {
if ((cmd->tgt_dev == tgt_dev) ||
((cmd->tgt_dev == NULL) &&
@@ -4361,8 +4352,8 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd)
spin_lock_irq(&sess->sess_list_lock);
TRACE_DBG("Searching in search cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->search_cmd_list,
TRACE_DBG("Searching in sess cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->sess_cmd_list,
sess_cmd_list_entry) {
if ((cmd->dev == dev) ||
((cmd->dev == NULL) &&
@@ -5698,10 +5689,19 @@ static struct scst_cmd *__scst_find_cmd_by_tag(struct scst_session *sess,
/* ToDo: hash list */
TRACE_DBG("%s (sess=%p, tag=%llu)", "Searching in search cmd list",
TRACE_DBG("%s (sess=%p, tag=%llu)", "Searching in sess cmd list",
sess, (long long unsigned int)tag);
list_for_each_entry(cmd, &sess->search_cmd_list,
list_for_each_entry(cmd, &sess->sess_cmd_list,
sess_cmd_list_entry) {
/*
* We must not count done commands, because they were
* submitted for transmittion. Otherwise we can have a race,
* when for some reason cmd's release delayed after
* transmittion and initiator sends cmd with the same tag =>
* it can be possible that a wrong cmd will be returned.
*/
if (cmd->done)
continue;
if (cmd->tag == tag)
goto out;
}
@@ -5725,9 +5725,17 @@ struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data,
spin_lock_irqsave(&sess->sess_list_lock, flags);
TRACE_DBG("Searching in search cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->search_cmd_list,
sess_cmd_list_entry) {
TRACE_DBG("Searching in sess cmd list (sess=%p)", sess);
list_for_each_entry(cmd, &sess->sess_cmd_list, sess_cmd_list_entry) {
/*
* We must not count done commands, because they were
* submitted for transmittion. Otherwise we can have a race,
* when for some reason cmd's release delayed after
* transmittion and initiator sends cmd with the same tag =>
* it can be possible that a wrong cmd will be returned.
*/
if (cmd->done)
continue;
if (cmp_fn(cmd, data))
goto out_unlock;
}