cmnd->scst_state = ISCSI_CMD_STATE_NEW;
cmnd->conn = conn;
cmnd->parent_req = parent;
- init_waitqueue_head(&cmnd->scst_waitQ);
if (parent == NULL) {
conn_get(conn);
return cpu_to_be32(ttt);
}
+int cmnd_rx_continue(struct iscsi_cmnd *req)
+{
+ struct iscsi_conn *conn = req->conn;
+ struct iscsi_session *session = conn->session;
+ struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
+ struct scst_cmd *scst_cmd = req->scst_cmd;
+ scst_data_direction dir;
+ int res = 0;
+
+ TRACE_ENTRY();
+
+ TRACE_DBG("scsi command: %02x", req_hdr->scb[0]);
+
+ if (unlikely(req->scst_state != ISCSI_CMD_STATE_AFTER_PREPROC)) {
+ TRACE_DBG("req %p is in %x state", req, req->scst_state);
+ if (req->scst_state == ISCSI_CMD_STATE_PROCESSED) {
+ cmnd_reject_scsi_cmd(req);
+ goto out;
+ }
+ if (unlikely(req->tm_aborted)) {
+ TRACE_MGMT_DBG("req %p (scst_cmd %p) aborted", req,
+ req->scst_cmd);
+ cmnd_prepare_get_rejected_cmd_data(req);
+ goto out;
+ }
+ sBUG();
+ }
+
+ dir = scst_cmd_get_data_direction(scst_cmd);
+ if (dir & SCST_DATA_WRITE) {
+ req->is_unsolicited_data = !(req_hdr->flags & ISCSI_CMD_FINAL);
+ req->r2t_length = be32_to_cpu(req_hdr->data_length) -
+ req->pdu.datasize;
+ if (req->r2t_length > 0)
+ req->data_waiting = 1;
+ } else {
+ if (unlikely(!(req_hdr->flags & ISCSI_CMD_FINAL) ||
+ req->pdu.datasize)) {
+ PRINT_ERROR("Unexpected unsolicited data (ITT %x "
+ "CDB %x", cmnd_itt(req), req_hdr->scb[0]);
+ scst_set_cmd_error(scst_cmd,
+ SCST_LOAD_SENSE(iscsi_sense_unexpected_unsolicited_data));
+ if (scst_cmd_get_sense_buffer(scst_cmd) != NULL)
+ create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
+ scst_cmd_get_sense_buffer(scst_cmd),
+ scst_cmd_get_sense_buffer_len(scst_cmd));
+ else
+ create_status_rsp(req, SAM_STAT_BUSY, NULL, 0);
+ cmnd_reject_scsi_cmd(req);
+ goto out;
+ }
+ }
+
+ req->target_task_tag = get_next_ttt(conn);
+ if (dir != SCST_DATA_BIDI) {
+ req->sg = scst_cmd_get_sg(scst_cmd);
+ req->sg_cnt = scst_cmd_get_sg_cnt(scst_cmd);
+ req->bufflen = scst_cmd_get_bufflen(scst_cmd);
+ } else {
+ req->sg = scst_cmd_get_in_sg(scst_cmd);
+ req->sg_cnt = scst_cmd_get_in_sg_cnt(scst_cmd);
+ req->bufflen = scst_cmd_get_in_bufflen(scst_cmd);
+ }
+ if (unlikely(req->r2t_length > req->bufflen)) {
+ PRINT_ERROR("req->r2t_length %d > req->bufflen %d",
+ req->r2t_length, req->bufflen);
+ req->r2t_length = req->bufflen;
+ }
+
+ TRACE_DBG("req=%p, dir=%d, is_unsolicited_data=%d, "
+ "r2t_length=%d, bufflen=%d", req, dir,
+ req->is_unsolicited_data, req->r2t_length, req->bufflen);
+
+ if (unlikely(!session->sess_param.immediate_data &&
+ req->pdu.datasize)) {
+ PRINT_ERROR("Initiator %s violated negotiated paremeters: "
+ "forbidden immediate data sent (ITT %x, op %x)",
+ session->initiator_name, cmnd_itt(req),
+ req_hdr->scb[0]);
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (unlikely(session->sess_param.initial_r2t &&
+ !(req_hdr->flags & ISCSI_CMD_FINAL))) {
+ PRINT_ERROR("Initiator %s violated negotiated paremeters: "
+ "initial R2T is required (ITT %x, op %x)",
+ session->initiator_name, cmnd_itt(req),
+ req_hdr->scb[0]);
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (req->pdu.datasize)
+ res = cmnd_prepare_recv_pdu(conn, req, 0, req->pdu.datasize);
+
+out:
+ /* Aborted commands will be freed in cmnd_rx_end() */
+ TRACE_EXIT_RES(res);
+ return res;
+}
+
static int scsi_cmnd_start(struct iscsi_cmnd *req)
{
struct iscsi_conn *conn = req->conn;
TRACE_DBG("START Command (tag %d, queue_type %d)",
req_hdr->itt, scst_cmd->queue_type);
req->scst_state = ISCSI_CMD_STATE_RX_CMD;
+ conn->rx_task = current;
scst_cmd_init_stage1_done(scst_cmd, SCST_CONTEXT_DIRECT, 0);
- wait_event(req->scst_waitQ, req->scst_state != ISCSI_CMD_STATE_RX_CMD);
-
- if (unlikely(req->scst_state != ISCSI_CMD_STATE_AFTER_PREPROC)) {
- TRACE_DBG("req %p is in %x state", req, req->scst_state);
- if (req->scst_state == ISCSI_CMD_STATE_PROCESSED) {
- cmnd_reject_scsi_cmd(req);
- goto out;
- }
- if (unlikely(req->tm_aborted)) {
- TRACE_MGMT_DBG("req %p (scst_cmd %p) aborted", req,
- req->scst_cmd);
- cmnd_prepare_get_rejected_cmd_data(req);
- goto out;
- }
- sBUG();
- }
-
- dir = scst_cmd_get_data_direction(scst_cmd);
- if (dir & SCST_DATA_WRITE) {
- req->is_unsolicited_data = !(req_hdr->flags & ISCSI_CMD_FINAL);
- req->r2t_length = be32_to_cpu(req_hdr->data_length) -
- req->pdu.datasize;
- if (req->r2t_length > 0)
- req->data_waiting = 1;
- } else {
- if (unlikely(!(req_hdr->flags & ISCSI_CMD_FINAL) ||
- req->pdu.datasize)) {
- PRINT_ERROR("Unexpected unsolicited data (ITT %x "
- "CDB %x", cmnd_itt(req), req_hdr->scb[0]);
- scst_set_cmd_error(scst_cmd,
- SCST_LOAD_SENSE(iscsi_sense_unexpected_unsolicited_data));
- if (scst_cmd_get_sense_buffer(scst_cmd) != NULL)
- create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
- scst_cmd_get_sense_buffer(scst_cmd),
- scst_cmd_get_sense_buffer_len(scst_cmd));
- else
- create_status_rsp(req, SAM_STAT_BUSY, NULL, 0);
- cmnd_reject_scsi_cmd(req);
- goto out;
- }
- }
-
- req->target_task_tag = get_next_ttt(conn);
- if (dir != SCST_DATA_BIDI) {
- req->sg = scst_cmd_get_sg(scst_cmd);
- req->sg_cnt = scst_cmd_get_sg_cnt(scst_cmd);
- req->bufflen = scst_cmd_get_bufflen(scst_cmd);
- } else {
- req->sg = scst_cmd_get_in_sg(scst_cmd);
- req->sg_cnt = scst_cmd_get_in_sg_cnt(scst_cmd);
- req->bufflen = scst_cmd_get_in_bufflen(scst_cmd);
- }
- if (unlikely(req->r2t_length > req->bufflen)) {
- PRINT_ERROR("req->r2t_length %d > req->bufflen %d",
- req->r2t_length, req->bufflen);
- req->r2t_length = req->bufflen;
- }
-
- TRACE_DBG("req=%p, dir=%d, is_unsolicited_data=%d, "
- "r2t_length=%d, bufflen=%d", req, dir,
- req->is_unsolicited_data, req->r2t_length, req->bufflen);
-
- if (unlikely(!session->sess_param.immediate_data &&
- req->pdu.datasize)) {
- PRINT_ERROR("Initiator %s violated negotiated paremeters: "
- "forbidden immediate data sent (ITT %x, op %x)",
- session->initiator_name, cmnd_itt(req),
- req_hdr->scb[0]);
- res = -EINVAL;
- goto out;
+ if (req->scst_state != ISCSI_CMD_STATE_RX_CMD)
+ res = cmnd_rx_continue(req);
+ else {
+ TRACE_DBG("Delaying req %p post processing (scst_state %d)",
+ req, req->scst_state);
+ res = 1;
}
- if (unlikely(session->sess_param.initial_r2t &&
- !(req_hdr->flags & ISCSI_CMD_FINAL))) {
- PRINT_ERROR("Initiator %s violated negotiated paremeters: "
- "initial R2T is required (ITT %x, op %x)",
- session->initiator_name, cmnd_itt(req),
- req_hdr->scb[0]);
- res = -EINVAL;
- goto out;
- }
-
- if (req->pdu.datasize)
- res = cmnd_prepare_recv_pdu(conn, req, 0, req->pdu.datasize);
out:
/* Aborted commands will be freed in cmnd_rx_end() */
TRACE_EXIT_RES(res);
static inline void iscsi_set_state_wake_up(struct iscsi_cmnd *req,
int new_state)
{
- /*
- * We use wait_event() to wait for the state change, but it checks its
- * condition without any protection, so without cmnd_get() it is
- * possible that req will die "immediately" after the state assignment
- * and wake_up() will operate on dead data. We use the ordered version
- * of cmnd_get(), because "get" must be done before the state
- * assignment.
- */
- cmnd_get_ordered(req);
- req->scst_state = new_state;
- wake_up(&req->scst_waitQ);
- cmnd_put(req);
+ if (req->conn->rx_task == current)
+ req->scst_state = new_state;
+ else {
+ /*
+ * We wait for the state change without any protection, so
+ * without cmnd_get() it is possible that req will die
+ * "immediately" after the state assignment and
+ * iscsi_make_conn_rd_active() will operate on dead data.
+ * We use the ordered version of cmnd_get(), because "get"
+ * must be done before the state assignment.
+ */
+ cmnd_get_ordered(req);
+ req->scst_state = new_state;
+ iscsi_make_conn_rd_active(req->conn);
+ if (unlikely(req->conn->closing)) {
+ TRACE_DBG("Waiking up closing conn %p", req->conn);
+ wake_up(&req->conn->read_state_waitQ);
+ }
+ cmnd_put(req);
+ }
return;
}
#include "digest.h"
enum rx_state {
- RX_INIT_BHS, /* Must be zero. */
+ RX_INIT_BHS, /* Must be zero for better "switch" optimiztion. */
RX_BHS,
+ RX_CMD_START,
+ RX_DATA,
+ RX_END,
- RX_INIT_AHS,
- RX_AHS,
-
+ RX_CMD_CONTINUE,
RX_INIT_HDIGEST,
- RX_HDIGEST,
RX_CHECK_HDIGEST,
-
- RX_INIT_DATA,
- RX_DATA,
-
- RX_INIT_PADDING,
- RX_PADDING,
-
RX_INIT_DDIGEST,
- RX_DDIGEST,
RX_CHECK_DDIGEST,
-
- RX_END,
+ RX_AHS,
+ RX_PADDING,
};
enum tx_state {
- TX_INIT, /* Must be zero. */
+ TX_INIT = 0, /* Must be zero for better "switch" optimiztion. */
TX_BHS_DATA,
TX_INIT_PADDING,
TX_PADDING,
if (conn->read_state != RX_INIT_BHS) {
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);
+ }
+ wait_event(conn->read_state_waitQ,
+ cmnd->scst_state != ISCSI_CMD_STATE_RX_CMD);
+
conn->read_cmnd = NULL;
conn->read_state = RX_INIT_BHS;
req_cmnd_release_force(cmnd, 0);
return;
}
-static void iscsi_conn_read_ahs(struct iscsi_conn *conn,
+static void iscsi_conn_prepare_read_ahs(struct iscsi_conn *conn,
struct iscsi_cmnd *cmnd)
{
int asize = (cmnd->pdu.ahssize + 3) & -4;
return cmnd;
}
-static int do_recv(struct iscsi_conn *conn, int state)
+/* Returns number of bytes left to receive or <0 for error */
+static int do_recv(struct iscsi_conn *conn)
{
- mm_segment_t oldfs;
- struct msghdr msg;
- int res, first_len;
+ int res;
- sBUG_ON(conn->read_cmnd == NULL);
+ EXTRACHECKS_BUG_ON(conn->read_cmnd == NULL);
- if (unlikely(conn->closing)) {
- res = -EIO;
- goto out;
- }
+ do {
+ mm_segment_t oldfs;
+ struct msghdr msg;
+ int first_len;
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = conn->read_msg.msg_iov;
- msg.msg_iovlen = conn->read_msg.msg_iovlen;
- first_len = msg.msg_iov->iov_len;
-
- oldfs = get_fs();
- set_fs(get_ds());
- res = sock_recvmsg(conn->sock, &msg, conn->read_size,
- MSG_DONTWAIT | MSG_NOSIGNAL);
- set_fs(oldfs);
-
- if (res <= 0) {
- switch (res) {
- case -EAGAIN:
- case -ERESTARTSYS:
- TRACE_DBG("EAGAIN or ERESTARTSYS (%d) received for "
- "conn %p", res, conn);
- break;
- default:
- PRINT_ERROR("sock_recvmsg() failed: %d", res);
- mark_conn_closed(conn);
- break;
+ if (unlikely(conn->closing)) {
+ res = -EIO;
+ goto out;
}
- } else {
- /*
- * To save some considerable effort and CPU power we suppose
- * that TCP functions adjust conn->read_msg.msg_iov and
- * conn->read_msg.msg_iovlen on amount of copied data. This
- * BUG_ON is intended to catch if it is changed in the future.
- */
- sBUG_ON((res >= first_len) &&
- (conn->read_msg.msg_iov->iov_len != 0));
- conn->read_size -= res;
- if (conn->read_size) {
- if (res >= first_len) {
- int done =
- 1 + ((res - first_len) >> PAGE_SHIFT);
- conn->read_msg.msg_iov += done;
- conn->read_msg.msg_iovlen -= done;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = conn->read_msg.msg_iov;
+ msg.msg_iovlen = conn->read_msg.msg_iovlen;
+ first_len = msg.msg_iov->iov_len;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+ res = sock_recvmsg(conn->sock, &msg, conn->read_size,
+ MSG_DONTWAIT | MSG_NOSIGNAL);
+ set_fs(oldfs);
+
+ if (res > 0) {
+ /*
+ * To save some considerable effort and CPU power we
+ * suppose that TCP functions adjust
+ * conn->read_msg.msg_iov and conn->read_msg.msg_iovlen
+ * on amount of copied data. This BUG_ON is intended
+ * to catch if it is changed in the future.
+ */
+ sBUG_ON((res >= first_len) &&
+ (conn->read_msg.msg_iov->iov_len != 0));
+ conn->read_size -= res;
+ if (conn->read_size != 0) {
+ if (res >= first_len) {
+ int done = 1 + ((res - first_len) >> PAGE_SHIFT);
+ conn->read_msg.msg_iov += done;
+ conn->read_msg.msg_iovlen -= done;
+ }
}
- } else
- conn->read_state = state;
- }
+ res = conn->read_size;
+ } else {
+ switch (res) {
+ case -EAGAIN:
+ TRACE_DBG("EAGAIN received for conn %p", conn);
+ res = conn->read_size;
+ break;
+ case -ERESTARTSYS:
+ TRACE_DBG("ERESTARTSYS received for conn %p", conn);
+ continue;
+ default:
+ PRINT_ERROR("sock_recvmsg() failed: %d", res);
+ mark_conn_closed(conn);
+ if (res == 0)
+ res = -EIO;
+ break;
+ }
+ break;
+ }
+ } while (res > 0);
out:
TRACE_EXIT_RES(res);
return res;
}
-static int rx_hdigest(struct iscsi_conn *conn)
+static int iscsi_rx_check_ddigest(struct iscsi_conn *conn)
{
struct iscsi_cmnd *cmnd = conn->read_cmnd;
- int res = digest_rx_header(cmnd);
-
- if (unlikely(res != 0)) {
- PRINT_ERROR("rx header digest for initiator %s failed "
- "(%d)", conn->session->initiator_name, res);
- mark_conn_closed(conn);
- }
- return res;
-}
-
-static struct iscsi_cmnd *create_cmnd(struct iscsi_conn *conn)
-{
- struct iscsi_cmnd *cmnd;
-
- cmnd = cmnd_alloc(conn, NULL);
- iscsi_conn_init_read(cmnd->conn, (void __force __user *)&cmnd->pdu.bhs,
- sizeof(cmnd->pdu.bhs));
- conn->read_state = RX_BHS;
-
- return cmnd;
-}
-
-/* Returns >0 for success, <=0 for error or successful finish */
-static int recv(struct iscsi_conn *conn)
-{
- struct iscsi_cmnd *cmnd = conn->read_cmnd;
- int hdigest, ddigest, res = 1, rc;
-
- TRACE_ENTRY();
-
- hdigest = conn->hdigest_type & DIGEST_NONE ? 0 : 1;
- ddigest = conn->ddigest_type & DIGEST_NONE ? 0 : 1;
-
- switch (conn->read_state) {
- case RX_INIT_BHS:
- sBUG_ON(cmnd != NULL);
- cmnd = conn->read_cmnd = create_cmnd(conn);
- case RX_BHS:
- res = do_recv(conn, RX_INIT_AHS);
- if (res <= 0 || conn->read_state != RX_INIT_AHS)
- break;
- case RX_INIT_AHS:
- iscsi_cmnd_get_length(&cmnd->pdu);
- if (cmnd->pdu.ahssize) {
- iscsi_conn_read_ahs(conn, cmnd);
- conn->read_state = RX_AHS;
- } else
- conn->read_state =
- hdigest ? RX_INIT_HDIGEST : RX_INIT_DATA;
+ int res;
- if (conn->read_state != RX_AHS)
- break;
- case RX_AHS:
- res = do_recv(conn, hdigest ? RX_INIT_HDIGEST : RX_INIT_DATA);
- if (res <= 0 || conn->read_state != RX_INIT_HDIGEST)
- break;
- case RX_INIT_HDIGEST:
- iscsi_conn_init_read(conn,
- (void __force __user *)&cmnd->hdigest, sizeof(u32));
- conn->read_state = RX_HDIGEST;
- case RX_HDIGEST:
- res = do_recv(conn, RX_CHECK_HDIGEST);
- if (res <= 0 || conn->read_state != RX_CHECK_HDIGEST)
- break;
- case RX_CHECK_HDIGEST:
- rc = rx_hdigest(conn);
- if (likely(rc == 0))
- conn->read_state = RX_INIT_DATA;
- else {
- res = rc;
- break;
- }
- case RX_INIT_DATA:
- rc = cmnd_rx_start(cmnd);
- if (unlikely(rc != 0)) {
- sBUG_ON(!conn->closing);
- conn->read_state = RX_END;
- res = rc;
- /* cmnd will be freed in close_conn() */
- goto out;
- }
- conn->read_state = cmnd->pdu.datasize ? RX_DATA : RX_END;
- if (conn->read_state != RX_DATA)
- break;
- case RX_DATA:
- res = do_recv(conn, RX_INIT_PADDING);
- if (res <= 0 || conn->read_state != RX_INIT_PADDING)
- break;
- case RX_INIT_PADDING:
- {
- int psz = ((cmnd->pdu.datasize + 3) & -4) - cmnd->pdu.datasize;
- if (psz != 0) {
- TRACE_DBG("padding %d bytes", psz);
- iscsi_conn_init_read(conn,
- (void __force __user *)&conn->rpadding, psz);
- conn->read_state = RX_PADDING;
- } else if (ddigest)
- conn->read_state = RX_INIT_DDIGEST;
- else
- conn->read_state = RX_END;
- break;
- }
- case RX_PADDING:
- res = do_recv(conn, ddigest ? RX_INIT_DDIGEST : RX_END);
- if (res <= 0 || conn->read_state != RX_INIT_DDIGEST)
- break;
- case RX_INIT_DDIGEST:
- iscsi_conn_init_read(conn,
- (void __force __user *)&cmnd->ddigest, sizeof(u32));
- conn->read_state = RX_DDIGEST;
- case RX_DDIGEST:
- res = do_recv(conn, RX_CHECK_DDIGEST);
- if (res <= 0 || conn->read_state != RX_CHECK_DDIGEST)
- break;
- case RX_CHECK_DDIGEST:
+ res = do_recv(conn);
+ if (res == 0) {
conn->read_state = RX_END;
+
if (cmnd->pdu.datasize <= 16*1024) {
/*
* It's cache hot, so let's compute it inline. The
TRACE_DBG("cmnd %p, opcode %x: checking RX "
"ddigest inline", cmnd, cmnd_opcode(cmnd));
cmnd->ddigest_checked = 1;
- rc = digest_rx_data(cmnd);
- if (unlikely(rc != 0)) {
+ res = digest_rx_data(cmnd);
+ if (unlikely(res != 0)) {
mark_conn_closed(conn);
goto out;
}
*/
TRACE_DBG("cmnd %p, opcode %x: checking NOP RX "
"ddigest", cmnd, cmnd_opcode(cmnd));
- rc = digest_rx_data(cmnd);
- if (unlikely(rc != 0)) {
+ res = digest_rx_data(cmnd);
+ if (unlikely(res != 0)) {
mark_conn_closed(conn);
goto out;
}
}
- break;
- default:
- PRINT_CRIT_ERROR("%d %x", conn->read_state, cmnd_opcode(cmnd));
- sBUG();
- }
-
- if (res <= 0)
- goto out;
-
- if (conn->read_state != RX_END)
- goto out;
-
- if (unlikely(conn->read_size)) {
- PRINT_CRIT_ERROR("%d %x %d", res, cmnd_opcode(cmnd),
- conn->read_size);
- sBUG();
- }
-
- conn->read_cmnd = NULL;
- conn->read_state = RX_INIT_BHS;
-
- cmnd_rx_end(cmnd);
-
- sBUG_ON(conn->read_size != 0);
-
- res = 0;
+ }
out:
- TRACE_EXIT_RES(res);
return res;
}
/* No locks, conn is rd processing */
-static int process_read_io(struct iscsi_conn *conn, int *closed)
+static void process_read_io(struct iscsi_conn *conn, int *closed)
{
+ struct iscsi_cmnd *cmnd = conn->read_cmnd;
int res;
+ TRACE_ENTRY();
+
+ /* In case of error cmnd will be freed in close_conn() */
+
do {
- res = recv(conn);
- if (unlikely(conn->closing)) {
- start_close_conn(conn);
- *closed = 1;
+ switch (conn->read_state) {
+ case RX_INIT_BHS:
+ EXTRACHECKS_BUG_ON(conn->read_cmnd != NULL);
+ cmnd = cmnd_alloc(conn, NULL);
+ conn->read_cmnd = cmnd;
+ iscsi_conn_init_read(cmnd->conn,
+ (void __force __user *)&cmnd->pdu.bhs,
+ sizeof(cmnd->pdu.bhs));
+ conn->read_state = RX_BHS;
+ /* go through */
+
+ case RX_BHS:
+ res = do_recv(conn);
+ if (res == 0) {
+ iscsi_cmnd_get_length(&cmnd->pdu);
+ if (cmnd->pdu.ahssize == 0) {
+ if ((conn->hdigest_type & DIGEST_NONE) == 0)
+ conn->read_state = RX_INIT_HDIGEST;
+ else
+ conn->read_state = RX_CMD_START;
+ } else {
+ iscsi_conn_prepare_read_ahs(conn, cmnd);
+ conn->read_state = RX_AHS;
+ }
+ }
+ break;
+
+ case RX_CMD_START:
+ res = cmnd_rx_start(cmnd);
+ if (res == 0) {
+ if (cmnd->pdu.datasize == 0)
+ conn->read_state = RX_END;
+ else
+ conn->read_state = RX_DATA;
+ } else if (res > 0)
+ conn->read_state = RX_CMD_CONTINUE;
+ else
+ sBUG_ON(!conn->closing);
break;
+
+ case RX_CMD_CONTINUE:
+ if (cmnd->scst_state == ISCSI_CMD_STATE_RX_CMD) {
+ TRACE_DBG("cmnd %p is still in RX_CMD state",
+ cmnd);
+ res = 1;
+ break;
+ }
+ res = cmnd_rx_continue(cmnd);
+ if (unlikely(res != 0))
+ sBUG_ON(!conn->closing);
+ else {
+ if (cmnd->pdu.datasize == 0)
+ conn->read_state = RX_END;
+ else
+ conn->read_state = RX_DATA;
+ }
+ break;
+
+ case RX_DATA:
+ res = do_recv(conn);
+ if (res == 0) {
+ int psz = ((cmnd->pdu.datasize + 3) & -4) - cmnd->pdu.datasize;
+ if (psz != 0) {
+ TRACE_DBG("padding %d bytes", psz);
+ iscsi_conn_init_read(conn,
+ (void __force __user *)&conn->rpadding, psz);
+ conn->read_state = RX_PADDING;
+ } else if ((conn->ddigest_type & DIGEST_NONE) != 0)
+ conn->read_state = RX_END;
+ else
+ conn->read_state = RX_INIT_DDIGEST;
+ }
+ break;
+
+ case RX_END:
+ if (unlikely(conn->read_size != 0)) {
+ PRINT_CRIT_ERROR("%d %x %d", res,
+ cmnd_opcode(cmnd), conn->read_size);
+ sBUG();
+ }
+ conn->read_cmnd = NULL;
+ conn->read_state = RX_INIT_BHS;
+
+ cmnd_rx_end(cmnd);
+
+ EXTRACHECKS_BUG_ON(conn->read_size != 0);
+ break;
+
+ case RX_INIT_HDIGEST:
+ iscsi_conn_init_read(conn,
+ (void __force __user *)&cmnd->hdigest, sizeof(u32));
+ conn->read_state = RX_CHECK_HDIGEST;
+ /* go through */
+
+ case RX_CHECK_HDIGEST:
+ res = do_recv(conn);
+ if (res == 0) {
+ res = digest_rx_header(cmnd);
+ if (unlikely(res != 0)) {
+ PRINT_ERROR("rx header digest for "
+ "initiator %s failed (%d)",
+ conn->session->initiator_name,
+ res);
+ mark_conn_closed(conn);
+ } else
+ conn->read_state = RX_CMD_START;
+ }
+ break;
+
+ case RX_INIT_DDIGEST:
+ iscsi_conn_init_read(conn,
+ (void __force __user *)&cmnd->ddigest,
+ sizeof(u32));
+ conn->read_state = RX_CHECK_DDIGEST;
+ /* go through */
+
+ case RX_CHECK_DDIGEST:
+ res = iscsi_rx_check_ddigest(conn);
+ break;
+
+ case RX_AHS:
+ res = do_recv(conn);
+ if (res == 0) {
+ if ((conn->hdigest_type & DIGEST_NONE) == 0)
+ conn->read_state = RX_INIT_HDIGEST;
+ else
+ conn->read_state = RX_CMD_START;
+ }
+ break;
+
+ case RX_PADDING:
+ res = do_recv(conn);
+ if (res == 0) {
+ if ((conn->ddigest_type & DIGEST_NONE) == 0)
+ conn->read_state = RX_INIT_DDIGEST;
+ else
+ conn->read_state = RX_END;
+ }
+ break;
+
+ default:
+ PRINT_CRIT_ERROR("%d %x", conn->read_state, cmnd_opcode(cmnd));
+ sBUG();
}
- } while (res > 0);
+ } while (res == 0);
- TRACE_EXIT_RES(res);
- return res;
+ if (unlikely(conn->closing)) {
+ start_close_conn(conn);
+ *closed = 1;
+ }
+
+ TRACE_EXIT();
+ return;
}
/*
*/
while (!list_empty(&iscsi_rd_list)) {
- int rc, closed = 0;
+ int closed = 0;
struct iscsi_conn *conn = list_entry(iscsi_rd_list.next,
typeof(*conn), rd_list_entry);
#endif
spin_unlock_bh(&iscsi_rd_lock);
- rc = process_read_io(conn, &closed);
+ process_read_io(conn, &closed);
spin_lock_bh(&iscsi_rd_lock);
#ifdef CONFIG_SCST_EXTRACHECKS
conn->rd_task = NULL;
#endif
- if ((rc == 0) || conn->rd_data_ready) {
+ if (conn->rd_data_ready) {
list_add_tail(&conn->rd_list_entry, &iscsi_rd_list);
conn->rd_state = ISCSI_CONN_RD_STATE_IN_LIST;
} else