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));
list_del(&conn->conn_list_entry);
static inline void iscsi_fail_waiting_cmnd(struct iscsi_cmnd *cmnd)
{
- TRACE_DBG("Failing data waiting cmd %p", cmnd);
+ TRACE_MGMT_DBG("Failing data waiting cmd %p", cmnd);
/*
* There is no race with conn_abort(), since all functions
if (unlikely(cmnd->on_write_list || cmnd->on_written_list)) {
struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd);
- PRINT_ERROR("cmnd %p still on some list?, %x, %x, %x, %x, %x, %x, %x",
+ PRINT_CRIT_ERROR("cmnd %p still on some list?, %x, %x, %x, %x, %x, %x, %x",
cmnd, req->opcode, req->scb[0], req->flags, req->itt,
be32_to_cpu(req->data_length),
req->cmd_sn, be32_to_cpu(cmnd->pdu.datasize));
if (unlikely(cmnd->parent_req)) {
struct iscsi_scsi_cmd_hdr *req =
cmnd_hdr(cmnd->parent_req);
- PRINT_ERROR("%p %x %u", req, req->opcode, req->scb[0]);
+ PRINT_CRIT_ERROR("%p %x %u", req, req->opcode, req->scb[0]);
}
sBUG();
}
scst_tgt_cmd_done(cmnd->scst_cmd);
break;
default:
- PRINT_ERROR("Unexpected cmnd scst state %d",
+ PRINT_CRIT_ERROR("Unexpected cmnd scst state %d",
cmnd->scst_state);
sBUG();
break;
"new value %d)", cmnd, sess,
atomic_read(&sess->active_cmds)-1);
atomic_dec(&sess->active_cmds);
+#ifdef EXTRACHECKS
+ if (unlikely(atomic_read(&sess->active_cmds) < 0)) {
+ PRINT_CRIT_ERROR("active_cmds < 0 (%d)!!",
+ atomic_read(&sess->active_cmds));
+ sBUG();
+ }
+#endif
}
cmnd_free(cmnd);
TRACE_ENTRY();
- TRACE_DBG("%p", req);
+ TRACE_MGMT_DBG("%p", req);
sBUG_ON(req == conn->read_cmnd);
spin_unlock_bh(&conn->write_list_lock);
list_for_each_entry_safe(rsp, t, &cmds_list, write_list_entry) {
+ TRACE_MGMT_DBG("Putting write rsp %p", rsp);
list_del(&rsp->write_list_entry);
cmnd_put(rsp);
}
* If both on_write_list and write_processing_started not set,
* we can safely put() rsp.
*/
+ TRACE_MGMT_DBG("Putting rsp %p", rsp);
cmnd_put(rsp);
goto again_rsp;
}
atomic_read(&sess->active_cmds)-1);
atomic_dec(&sess->active_cmds);
req->dec_active_cmnds = 0;
+#ifdef EXTRACHECKS
+ if (unlikely(atomic_read(&sess->active_cmds) < 0)) {
+ PRINT_CRIT_ERROR("active_cmds < 0 (%d)!!",
+ atomic_read(&sess->active_cmds));
+ sBUG();
+ }
+#endif
}
cmnd_put(req);
LIST_HEAD(head);
if (unlikely(rsp->on_write_list)) {
- PRINT_ERROR("cmd already on write list (%x %x %x %x %u %u "
+ PRINT_CRIT_ERROR("cmd already on write list (%x %x %x %x %u %u "
"%u %u %u %u %u %d %d",
cmnd_itt(rsp), cmnd_ttt(rsp), cmnd_opcode(rsp),
cmnd_scsicode(rsp), rsp->r2t_sn,
cmnd_put(cmnd);
err = 0;
- } else
+ } else {
+ TRACE_MGMT_DBG("cmd RTT %x not found", req_hdr->rtt);
err = ISCSI_RESPONSE_UNKNOWN_TASK;
+ }
out:
return err;
ISCSI_RESPONSE_FUNCTION_UNSUPPORTED);
break;
default:
+ PRINT_ERROR("Unknown TM function %d", function);
iscsi_send_task_mgmt_resp(req,
ISCSI_RESPONSE_FUNCTION_REJECTED);
break;
case ISCSI_OP_LOGOUT_RSP:
break;
default:
- PRINT_ERROR("unexpected cmnd op %x", cmnd_opcode(cmnd));
+ PRINT_CRIT_ERROR("unexpected cmnd op %x", cmnd_opcode(cmnd));
sBUG();
break;
}
if (unlikely((req->bufflen != 0) &&
!(resp_flags & SCST_TSC_FLAG_STATUS))) {
- PRINT_ERROR("%s", "Sending DATA without STATUS is unsupported");
+ PRINT_CRIT_ERROR("%s", "Sending DATA without STATUS is unsupported");
scst_set_cmd_error(scst_cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
resp_flags = scst_cmd_get_tgt_resp_flags(scst_cmd);
struct iscsi_cmnd {
struct iscsi_conn *conn;
- /* Some flags protected by conn->write_list_lock */
+ /*
+ * Some flags protected by conn->write_list_lock, but all modified only
+ * from single read thread or when there are no references to cmd.
+ */
unsigned int hashed:1;
unsigned int should_close_conn:1;
unsigned int pending:1;
unsigned int force_cleanup_done:1;
unsigned int dec_active_cmnds:1;
unsigned int ddigest_checked:1;
- unsigned int on_written_list:1;
#ifdef EXTRACHECKS
unsigned int on_rx_digest_list:1;
unsigned int release_called:1;
struct list_head write_list_entry;
};
+ /* Both modified only from single write thread */
+ unsigned int on_written_list:1;
unsigned long write_timeout;
/*
#ifdef DEBUG
#define ISCSI_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_LINE | TRACE_PID | \
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | TRACE_MGMT_DEBUG | \
- TRACE_MINOR | TRACE_SPECIAL | TRACE_CONN_OC)
+ TRACE_MINOR | TRACE_SPECIAL | TRACE_CONN_OC | TRACE_CONN_OC_DBG)
#else
#define ISCSI_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
TRACE_MINOR | TRACE_SPECIAL)
if ((conn->sock->sk->sk_state != TCP_CLOSE_WAIT) &&
(conn->sock->sk->sk_state != TCP_CLOSE)) {
- TRACE_CONN_CLOSE_DBG("sk_state %d, skipping",
+ TRACE_CONN_CLOSE("sk_state %d, skipping",
conn->sock->sk->sk_state);
goto out;
}
conn->sock->sk->sk_write_space = conn->old_write_space;
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
- while(conn->wr_state != ISCSI_CONN_WR_STATE_IDLE) {
+ while(1) {
+ bool t;
+
+ spin_lock_bh(&iscsi_wr_lock);
+ t = (conn->wr_state == ISCSI_CONN_WR_STATE_IDLE);
+ spin_unlock_bh(&iscsi_wr_lock);
+
+ if (t && (atomic_read(&conn->conn_ref_cnt) == 0))
+ break;
+
TRACE_CONN_CLOSE("Waiting for wr thread (conn %p), wr_state %x",
conn, conn->wr_state);
msleep(50);
wait_for_completion(&session->unreg_compl);
+ sBUG_ON(!session->shutting_down);
+
mutex_lock(&target->target_mutex);
conn_free(conn);
/* ToDo: this is incompatible with MC/S */
}
break;
default:
- PRINT_ERROR("%d %x", conn->read_state, cmnd_opcode(cmnd));
+ PRINT_CRIT_ERROR("%d %x", conn->read_state, cmnd_opcode(cmnd));
sBUG();
}
goto out;
if (unlikely(conn->read_size)) {
- PRINT_ERROR("%d %x %d", res, cmnd_opcode(cmnd), conn->read_size);
+ PRINT_CRIT_ERROR("%d %x %d", res, cmnd_opcode(cmnd),
+ conn->read_size);
sBUG();
}
}
if (!timer_pending(&conn->rsp_timer)) {
- sBUG_ON(!ref_cmd->write_timeout);
+ 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)",
#ifdef NET_PAGE_CALLBACKS_DEFINED
if (unlikely((sg_page(&sg[idx])->net_priv != NULL) &&
(sg_page(&sg[idx])->net_priv != ref_cmd))) {
- PRINT_ERROR("net_priv isn't NULL and != ref_cmd "
+ PRINT_CRIT_ERROR("net_priv isn't NULL and != ref_cmd "
"(write_cmnd %p, ref_cmd %p, sg %p, idx %d, "
"net_priv %p)", write_cmnd, ref_cmd, sg, idx,
sg_page(&sg[idx])->net_priv);
res = tx_ddigest(cmnd, TX_END);
break;
default:
- PRINT_ERROR("%d %d %x", res, conn->write_state,
+ PRINT_CRIT_ERROR("%d %d %x", res, conn->write_state,
cmnd_opcode(cmnd));
sBUG();
}
goto out;
if (unlikely(conn->write_size)) {
- PRINT_ERROR("%d %x %u", res, cmnd_opcode(cmnd),
+ PRINT_CRIT_ERROR("%d %x %u", res, cmnd_opcode(cmnd),
conn->write_size);
sBUG();
}
sBUG_ON(!list_empty(&session->conn_list));
if (unlikely(atomic_read(&session->active_cmds) != 0)) {
- PRINT_ERROR("active_cmds not 0 (%d)!!",
+ PRINT_CRIT_ERROR("active_cmds not 0 (%d)!!",
atomic_read(&session->active_cmds));
sBUG();
}
}
default:
- PRINT_ERROR("Wrong ucmd state %x", state);
+ PRINT_CRIT_ERROR("Wrong ucmd state %x", state);
sBUG();
break;
}
{0x03, "MMMMMMMMMMMMMMMM", "REQUEST SENSE",
SCST_DATA_READ, SCST_SMALL_TIMEOUT, 4, get_trans_len_1},
{0x04, "M O O ", "FORMAT UNIT",
- SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
+ SCST_DATA_WRITE, SCST_LONG_TIMEOUT|SCST_UNKNOWN_LENGTH, 0, get_trans_len_none},
{0x04, " O ", "FORMAT",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0x05, "VMVVVV V ", "READ BLOCK LIMITS",
#ifdef EXTRACHECKS
if (!list_empty(&dev->dev_tgt_dev_list) ||
!list_empty(&dev->dev_acg_dev_list)) {
- PRINT_ERROR("%s: dev_tgt_dev_list or dev_acg_dev_list "
+ PRINT_CRIT_ERROR("%s: dev_tgt_dev_list or dev_acg_dev_list "
"is not empty!", __FUNCTION__);
sBUG();
}
#ifdef EXTRACHECKS
if (unlikely(sess->shut_phase != SCST_SESS_SPH_READY)) {
- PRINT_ERROR("%s", "New cmd while shutting down the session");
+ PRINT_CRIT_ERROR("%s", "New cmd while shutting down the session");
sBUG();
}
#endif
if (scst_cmd_is_expected_set(cmd)) {
/*
* Command data length can't be easily
- * determined from the CDB. ToDo, that should
- * be fixed. Until it's fixed, get it from
- * the supplied expected value, but
- * limit it to some reasonable value (15MB).
+ * determined from the CDB. ToDo, all such
+ * commands should be fixed. Until they are
+ * fixed, get it from the supplied expected
+ * value, but limit it to some reasonable
+ * value (15MB).
*/
cmd->bufflen = min(cmd->expected_transfer_len,
15*1024*1024);
+ cmd->op_flags &= ~SCST_UNKNOWN_LENGTH;
} else
cmd->bufflen = 0;
}
break;
default:
- PRINT_ERROR("cmd (%p) in state %d, but shouldn't be",
- cmd, cmd->state);
+ PRINT_CRIT_ERROR("cmd (%p) in state %d, but shouldn't "
+ "be", cmd, cmd->state);
sBUG();
res = SCST_CMD_STATE_RES_CONT_NEXT;
break;
/* not very valid commands */
case SCST_CMD_STATE_DEFAULT:
case SCST_CMD_STATE_NEED_THREAD_CTX:
- PRINT_ERROR("cmd %p is in state %d, not putting on "
+ PRINT_CRIT_ERROR("cmd %p is in state %d, not putting on "
"useful list (left on scst cmd list)", cmd,
cmd->state);
spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock);
scst_sess_get(sess);
if (unlikely(sess->shut_phase != SCST_SESS_SPH_READY)) {
- PRINT_ERROR("New mgmt cmd while shutting down the session %p "
+ PRINT_CRIT_ERROR("New mgmt cmd while shutting down the session %p "
"shut_phase %ld", sess, sess->shut_phase);
sBUG();
}
if (sess->init_phase == SCST_SESS_IPH_INITING)
scst_init_session(sess);
else {
- PRINT_ERROR("session %p is in "
+ PRINT_CRIT_ERROR("session %p is in "
"scst_sess_init_list, but in unknown "
"init phase %x", sess,
sess->init_phase);
scst_free_session_callback(sess);
break;
default:
- PRINT_ERROR("session %p is in "
+ PRINT_CRIT_ERROR("session %p is in "
"scst_sess_shut_list, but in unknown "
"shut phase %lx", sess,
sess->shut_phase);