mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-18 05:06:31 +00:00
- Rejecting command reimplemented in a more simple, straightforward and readable way.
- Minor external interface change: now target drivers should set for aborted commands SCST_CMD_DELIVERY_ABORTED status via scst_set_delivery_status(). In-tree drivers updated. - Fixed broken compilation if put_page_callback patch not applied to the kernel. Reported by Erez Zilber <erezz@Voltaire.COM> - Fixed several minor problems reported by David Berton <davidbrt@yahoo.com> - Fixed __exit misuse, when such functions called from __init functions. - Docs updated. - Other minor changes and cleanups. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@364 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -162,6 +162,9 @@ 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;
|
||||
@@ -169,11 +172,6 @@ int digest_rx_data(struct iscsi_cmnd *cmnd)
|
||||
offset = be32_to_cpu(req_hdr->buffer_offset);
|
||||
break;
|
||||
|
||||
case ISCSI_OP_SCSI_REJECT:
|
||||
case ISCSI_OP_PDU_REJECT:
|
||||
case ISCSI_OP_DATA_REJECT:
|
||||
goto out;
|
||||
|
||||
default:
|
||||
req = cmnd;
|
||||
offset = 0;
|
||||
|
||||
+126
-71
@@ -61,7 +61,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 cmnd_prepare_get_rejected_cmd_data(struct iscsi_cmnd *cmnd);
|
||||
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess);
|
||||
static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd);
|
||||
|
||||
@@ -149,7 +149,6 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, struct iscsi_cmnd *parent
|
||||
#ifdef NET_PAGE_CALLBACKS_DEFINED
|
||||
atomic_set(&cmnd->net_ref_cnt, 0);
|
||||
#endif
|
||||
cmnd->target = conn->target;
|
||||
spin_lock_init(&cmnd->rsp_cmd_lock);
|
||||
INIT_LIST_HEAD(&cmnd->rsp_cmd_list);
|
||||
INIT_LIST_HEAD(&cmnd->rx_ddigest_cmd_list);
|
||||
@@ -168,7 +167,7 @@ void cmnd_free(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
TRACE_DBG("%p", cmnd);
|
||||
|
||||
if (unlikely(cmnd->tmfabort)) {
|
||||
if (unlikely(cmnd->tm_aborted)) {
|
||||
TRACE_MGMT_DBG("Free aborted cmd %p (scst cmd %p, state %d, "
|
||||
"parent_req %p)", cmnd, cmnd->scst_cmd, cmnd->scst_state,
|
||||
cmnd->parent_req);
|
||||
@@ -203,7 +202,7 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
TRACE_DBG("%p", cmnd);
|
||||
|
||||
if (unlikely(cmnd->tmfabort)) {
|
||||
if (unlikely(cmnd->tm_aborted)) {
|
||||
TRACE_MGMT_DBG("Done aborted cmd %p (scst cmd %p, state %d, "
|
||||
"parent_req %p)", cmnd, cmnd->scst_cmd, cmnd->scst_state,
|
||||
cmnd->parent_req);
|
||||
@@ -238,6 +237,10 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
|
||||
if (cmnd->scst_cmd) {
|
||||
switch(cmnd->scst_state) {
|
||||
case ISCSI_CMD_STATE_PROCESSED:
|
||||
TRACE_DBG("cmd %p PROCESSED", cmnd);
|
||||
scst_tgt_cmd_done(cmnd->scst_cmd);
|
||||
break;
|
||||
case ISCSI_CMD_STATE_AFTER_PREPROC:
|
||||
{
|
||||
struct scst_cmd *scst_cmd = cmnd->scst_cmd;
|
||||
@@ -249,10 +252,6 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
SCST_CONTEXT_THREAD);
|
||||
break;
|
||||
}
|
||||
case ISCSI_CMD_STATE_PROCESSED:
|
||||
TRACE_DBG("cmd %p PROCESSED", cmnd);
|
||||
scst_tgt_cmd_done(cmnd->scst_cmd);
|
||||
break;
|
||||
default:
|
||||
PRINT_CRIT_ERROR("Unexpected cmnd scst state %d",
|
||||
cmnd->scst_state);
|
||||
@@ -398,7 +397,7 @@ void req_cmnd_release(struct iscsi_cmnd *req)
|
||||
req->release_called = 1;
|
||||
#endif
|
||||
|
||||
if (unlikely(req->tmfabort)) {
|
||||
if (unlikely(req->tm_aborted)) {
|
||||
TRACE_MGMT_DBG("Release aborted req cmd %p (scst cmd %p, "
|
||||
"state %d)", req, req->scst_cmd, req->scst_state);
|
||||
}
|
||||
@@ -717,6 +716,10 @@ static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason)
|
||||
|
||||
TRACE_MGMT_DBG("Reject: req %p, reason %x", req, reason);
|
||||
|
||||
sBUG_ON(req->rejected);
|
||||
req->rejected = 1;
|
||||
req->reject_reason = ISCSI_REJECT_CMD;
|
||||
|
||||
rsp = iscsi_cmnd_create_rsp_cmnd(req);
|
||||
rsp_hdr = (struct iscsi_reject_hdr *)&rsp->pdu.bhs;
|
||||
|
||||
@@ -735,9 +738,11 @@ static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason)
|
||||
clear_page(addr);
|
||||
memcpy(addr, &req->pdu.bhs, sizeof(struct iscsi_hdr));
|
||||
rsp->bufflen = rsp->pdu.datasize = sizeof(struct iscsi_hdr);
|
||||
cmnd_prepare_skip_pdu(req);
|
||||
|
||||
req->pdu.bhs.opcode = ISCSI_OP_PDU_REJECT;
|
||||
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH |
|
||||
ISCSI_INIT_WRITE_WAKE);
|
||||
|
||||
cmnd_prepare_get_rejected_cmd_data(req);
|
||||
}
|
||||
|
||||
static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess)
|
||||
@@ -913,7 +918,7 @@ static void cmnd_remove_hash(struct iscsi_cmnd *cmnd)
|
||||
spin_unlock(&session->cmnd_hash_lock);
|
||||
}
|
||||
|
||||
static void cmnd_prepare_skip_pdu(struct iscsi_cmnd *cmnd)
|
||||
static void cmnd_prepare_get_rejected_cmd_data(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
struct iscsi_conn *conn = cmnd->conn;
|
||||
struct scatterlist *sg = cmnd->sg;
|
||||
@@ -954,9 +959,11 @@ static void cmnd_prepare_skip_pdu(struct iscsi_cmnd *cmnd)
|
||||
conn->read_iov[i].iov_len = size;
|
||||
conn->read_msg.msg_iov = conn->read_iov;
|
||||
conn->read_msg.msg_iovlen = ++i;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void cmnd_prepare_skip_pdu_set_resid(struct iscsi_cmnd *req)
|
||||
static void cmnd_reject_scsi_cmd(struct iscsi_cmnd *req)
|
||||
{
|
||||
struct iscsi_cmnd *rsp;
|
||||
struct iscsi_scsi_rsp_hdr *rsp_hdr;
|
||||
@@ -964,9 +971,15 @@ static void cmnd_prepare_skip_pdu_set_resid(struct iscsi_cmnd *req)
|
||||
|
||||
TRACE_DBG("%p", req);
|
||||
|
||||
sBUG_ON(req->rejected);
|
||||
req->rejected = 1;
|
||||
req->reject_reason = ISCSI_REJECT_SCSI_CMD;
|
||||
|
||||
rsp = get_rsp_cmnd(req);
|
||||
if (rsp == NULL)
|
||||
goto skip;
|
||||
if (rsp == NULL) {
|
||||
/* That can be true for aborted commands */
|
||||
goto out_reject;
|
||||
}
|
||||
|
||||
rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs;
|
||||
|
||||
@@ -988,11 +1001,12 @@ static void cmnd_prepare_skip_pdu_set_resid(struct iscsi_cmnd *req)
|
||||
}
|
||||
}
|
||||
|
||||
skip:
|
||||
req->pdu.bhs.opcode =
|
||||
(req->pdu.bhs.opcode & ~ISCSI_OPCODE_MASK) | ISCSI_OP_SCSI_REJECT;
|
||||
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH |
|
||||
ISCSI_INIT_WRITE_WAKE);
|
||||
|
||||
cmnd_prepare_skip_pdu(req);
|
||||
out_reject:
|
||||
cmnd_prepare_get_rejected_cmd_data(req);
|
||||
return;
|
||||
}
|
||||
|
||||
static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn,
|
||||
@@ -1065,7 +1079,7 @@ static void send_r2t(struct iscsi_cmnd *req)
|
||||
u32 offset, burst;
|
||||
LIST_HEAD(send);
|
||||
|
||||
if (unlikely(req->tmfabort)) {
|
||||
if (unlikely(req->tm_aborted)) {
|
||||
TRACE_MGMT_DBG("req %p (scst_cmd %p) aborted on R2T "
|
||||
"(r2t_length %d, outstanding_r2t %d)", req,
|
||||
req->scst_cmd, req->r2t_length, req->outstanding_r2t);
|
||||
@@ -1289,7 +1303,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
req_hdr->scb, sizeof(req_hdr->scb), SCST_NON_ATOMIC);
|
||||
if (scst_cmd == NULL) {
|
||||
create_status_rsp(req, SAM_STAT_BUSY, NULL, 0);
|
||||
cmnd_prepare_skip_pdu_set_resid(req);
|
||||
cmnd_reject_scsi_cmd(req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1344,13 +1358,13 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
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_prepare_skip_pdu_set_resid(req);
|
||||
cmnd_reject_scsi_cmd(req);
|
||||
goto out;
|
||||
}
|
||||
if (unlikely(req->tmfabort)) {
|
||||
if (unlikely(req->tm_aborted)) {
|
||||
TRACE_MGMT_DBG("req %p (scst_cmd %p) aborted", req,
|
||||
req->scst_cmd);
|
||||
cmnd_prepare_skip_pdu(req);
|
||||
cmnd_prepare_get_rejected_cmd_data(req);
|
||||
goto out;
|
||||
}
|
||||
sBUG();
|
||||
@@ -1363,7 +1377,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
PRINT_ERROR("Unexpected unsolicited data (ITT %x "
|
||||
"CDB %x", cmnd_itt(req), req_hdr->scb[0]);
|
||||
create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc);
|
||||
cmnd_prepare_skip_pdu_set_resid(req);
|
||||
cmnd_reject_scsi_cmd(req);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1411,7 +1425,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
PRINT_ERROR("pdu.datasize(%d) >0, but dir(%x) isn't WRITE",
|
||||
req->pdu.datasize, dir);
|
||||
create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc);
|
||||
cmnd_prepare_skip_pdu_set_resid(req);
|
||||
cmnd_reject_scsi_cmd(req);
|
||||
} else
|
||||
res = cmnd_prepare_recv_pdu(conn, req, 0, req->pdu.datasize);
|
||||
}
|
||||
@@ -1424,7 +1438,7 @@ out:
|
||||
static int data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
struct iscsi_data_out_hdr *req_hdr = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs;
|
||||
struct iscsi_cmnd *req = NULL;
|
||||
struct iscsi_cmnd *orig_req = NULL;
|
||||
u32 offset = be32_to_cpu(req_hdr->buffer_offset);
|
||||
int res = 0;
|
||||
|
||||
@@ -1438,29 +1452,29 @@ static int data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
|
||||
|
||||
update_stat_sn(cmnd);
|
||||
|
||||
cmnd->cmd_req = req = cmnd_find_hash(conn->session, req_hdr->itt,
|
||||
cmnd->cmd_req = orig_req = cmnd_find_hash(conn->session, req_hdr->itt,
|
||||
req_hdr->ttt);
|
||||
if (unlikely(req == NULL)) {
|
||||
if (unlikely(orig_req == NULL)) {
|
||||
/* 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;
|
||||
goto out_reject;
|
||||
}
|
||||
|
||||
if (req->is_unsolicited_data) {
|
||||
if (unlikely(req->r2t_length < cmnd->pdu.datasize)) {
|
||||
if (orig_req->is_unsolicited_data) {
|
||||
if (unlikely(orig_req->r2t_length < cmnd->pdu.datasize)) {
|
||||
PRINT_ERROR("Data size (%d) > R2T length (%d)",
|
||||
cmnd->pdu.datasize, req->r2t_length);
|
||||
cmnd->pdu.datasize, orig_req->r2t_length);
|
||||
mark_conn_closed(conn);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
req->r2t_length -= cmnd->pdu.datasize;
|
||||
orig_req->r2t_length -= cmnd->pdu.datasize;
|
||||
}
|
||||
|
||||
/* Check unsolicited burst data */
|
||||
if (unlikely((req_hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) &&
|
||||
(req->pdu.bhs.flags & ISCSI_FLG_FINAL))) {
|
||||
(orig_req->pdu.bhs.flags & ISCSI_FLG_FINAL))) {
|
||||
PRINT_ERROR("Unexpected data from %x %x",
|
||||
cmnd_itt(cmnd), cmnd_ttt(cmnd));
|
||||
mark_conn_closed(conn);
|
||||
@@ -1468,18 +1482,20 @@ static int data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE_WRITE("%u %p %p %u %u", req_hdr->ttt, cmnd, req,
|
||||
TRACE_WRITE("%u %p %p %u %u", req_hdr->ttt, cmnd, orig_req,
|
||||
offset, cmnd->pdu.datasize);
|
||||
|
||||
res = cmnd_prepare_recv_pdu(conn, req, offset, cmnd->pdu.datasize);
|
||||
res = cmnd_prepare_recv_pdu(conn, orig_req, offset, cmnd->pdu.datasize);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
skip_pdu:
|
||||
cmnd->pdu.bhs.opcode = ISCSI_OP_DATA_REJECT;
|
||||
cmnd_prepare_skip_pdu(cmnd);
|
||||
out_reject:
|
||||
sBUG_ON(cmnd->rejected);
|
||||
cmnd->rejected = 1;
|
||||
cmnd->reject_reason = ISCSI_REJECT_DATA;
|
||||
cmnd_prepare_get_rejected_cmd_data(cmnd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1543,6 +1559,23 @@ out_put:
|
||||
|
||||
static void __cmnd_abort(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
/*
|
||||
* Here, if cmnd is data_waiting, we should iscsi_fail_waiting_cmnd()
|
||||
* it. But, since this function can be called from any thread, not only
|
||||
* from the read one, we at the moment can't do that, because of
|
||||
* absence of appropriate locking protection. But this isn't a stuff
|
||||
* for 0.9.6. So, currently a misbehaving initiator, not sending
|
||||
* data in R2T state for a sharing between targets device, for which
|
||||
* for some reason an aborting TM command, e.g. TARGET RESET, from
|
||||
* another initiator is issued, can block response for this TM command
|
||||
* virtually forever and by this make the issuing initiator eventually
|
||||
* put the device offline.
|
||||
*
|
||||
* ToDo in the next version, possibly a simple connection mutex, taken
|
||||
* by the read thread before starting any processing and by this
|
||||
* function, should be sufficient.
|
||||
*/
|
||||
|
||||
TRACE_MGMT_DBG("Aborting cmd %p, scst_cmd %p (scst state %x, "
|
||||
"ref_cnt %d, itt %x, sn %u, op %x, r2t_len %x, CDB op %x, "
|
||||
"size to write %u, is_unsolicited_data %d, "
|
||||
@@ -1559,7 +1592,7 @@ static void __cmnd_abort(struct iscsi_cmnd *cmnd)
|
||||
TRACE_MGMT_DBG("net_ref_cnt %d", atomic_read(&cmnd->net_ref_cnt));
|
||||
#endif
|
||||
|
||||
cmnd->tmfabort = 1;
|
||||
cmnd->tm_aborted = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1949,16 +1982,21 @@ static void logout_exec(struct iscsi_cmnd *req)
|
||||
|
||||
static void iscsi_cmnd_exec(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("%p,%x,%u", cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn);
|
||||
|
||||
if (unlikely(cmnd->tmfabort)) {
|
||||
iscsi_extracheck_is_rd_thread(cmnd->conn);
|
||||
|
||||
if (unlikely(cmnd->tm_aborted)) {
|
||||
TRACE_MGMT_DBG("cmnd %p (scst_cmd %p) aborted", cmnd,
|
||||
cmnd->scst_cmd);
|
||||
req_cmnd_release_force(cmnd, ISCSI_FORCE_RELEASE_WRITE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
iscsi_extracheck_is_rd_thread(cmnd->conn);
|
||||
if (unlikely(cmnd->rejected))
|
||||
goto out_rejected;
|
||||
|
||||
switch (cmnd_opcode(cmnd)) {
|
||||
case ISCSI_OP_SCSI_CMD:
|
||||
@@ -1979,24 +2017,27 @@ static void iscsi_cmnd_exec(struct iscsi_cmnd *cmnd)
|
||||
case ISCSI_OP_LOGOUT_CMD:
|
||||
logout_exec(cmnd);
|
||||
break;
|
||||
case ISCSI_OP_SCSI_REJECT:
|
||||
{
|
||||
struct iscsi_cmnd *rsp = get_rsp_cmnd(cmnd);
|
||||
TRACE_MGMT_DBG("REJECT cmnd %p (scst_cmd %p), rsp %p", cmnd,
|
||||
cmnd->scst_cmd, rsp);
|
||||
if (rsp != NULL)
|
||||
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH |
|
||||
ISCSI_INIT_WRITE_WAKE);
|
||||
req_cmnd_release(cmnd);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PRINT_ERROR("unexpected cmnd op %x", cmnd_opcode(cmnd));
|
||||
req_cmnd_release(cmnd);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
|
||||
out_rejected:
|
||||
TRACE_MGMT_DBG("Rejected cmd %p (reason %d)", cmnd,
|
||||
cmnd->reject_reason);
|
||||
switch (cmnd->reject_reason) {
|
||||
default:
|
||||
PRINT_ERROR("Unexpected reject reason %d", cmnd->reject_reason);
|
||||
/* go through */
|
||||
case ISCSI_REJECT_SCSI_CMD:
|
||||
req_cmnd_release(cmnd);
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void __cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd,
|
||||
@@ -2238,7 +2279,7 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(cmnd->tmfabort)) {
|
||||
if (unlikely(cmnd->tm_aborted)) {
|
||||
struct iscsi_cmnd *tm_clone;
|
||||
|
||||
TRACE_MGMT_DBG("Pending aborted cmnd %p, creating TM "
|
||||
@@ -2247,7 +2288,7 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
|
||||
|
||||
tm_clone = cmnd_alloc(cmnd->conn, NULL);
|
||||
if (tm_clone != NULL) {
|
||||
tm_clone->tmfabort = 1;
|
||||
tm_clone->tm_aborted = 1;
|
||||
tm_clone->pdu = cmnd->pdu;
|
||||
|
||||
TRACE_MGMT_DBG("TM clone %p created", tm_clone);
|
||||
@@ -2353,9 +2394,12 @@ void cmnd_rx_end(struct iscsi_cmnd *cmnd)
|
||||
|
||||
TRACE_DBG("%p:%x", cmnd, cmnd_opcode(cmnd));
|
||||
|
||||
if (unlikely(cmnd->rejected))
|
||||
goto out_rejected;
|
||||
|
||||
cont:
|
||||
switch (cmnd_opcode(cmnd)) {
|
||||
case ISCSI_OP_SCSI_CMD:
|
||||
case ISCSI_OP_SCSI_REJECT:
|
||||
case ISCSI_OP_NOOP_OUT:
|
||||
case ISCSI_OP_SCSI_TASK_MGT_MSG:
|
||||
case ISCSI_OP_LOGOUT_CMD:
|
||||
@@ -2364,26 +2408,29 @@ void cmnd_rx_end(struct iscsi_cmnd *cmnd)
|
||||
case ISCSI_OP_SCSI_DATA_OUT:
|
||||
data_out_end(cmnd);
|
||||
break;
|
||||
case ISCSI_OP_PDU_REJECT:
|
||||
{
|
||||
struct iscsi_cmnd *rsp = get_rsp_cmnd(cmnd);
|
||||
if (rsp != NULL)
|
||||
iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_REMOVE_HASH |
|
||||
ISCSI_INIT_WRITE_WAKE);
|
||||
req_cmnd_release(cmnd);
|
||||
break;
|
||||
}
|
||||
case ISCSI_OP_DATA_REJECT:
|
||||
req_cmnd_release(cmnd);
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR("unexpected cmnd op %x", cmnd_opcode(cmnd));
|
||||
req_cmnd_release(cmnd);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
|
||||
out_rejected:
|
||||
switch (cmnd->reject_reason) {
|
||||
default:
|
||||
PRINT_ERROR("Unexpected reject reason %d", cmnd->reject_reason);
|
||||
/* go through */
|
||||
case ISCSI_REJECT_CMD:
|
||||
case ISCSI_REJECT_DATA:
|
||||
req_cmnd_release(cmnd);
|
||||
break;
|
||||
case ISCSI_REJECT_SCSI_CMD:
|
||||
goto cont;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef NET_PAGE_CALLBACKS_DEFINED
|
||||
@@ -2512,21 +2559,28 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
|
||||
|
||||
scst_cmd_set_tgt_priv(scst_cmd, NULL);
|
||||
|
||||
req->tmfabort |= scst_cmd_aborted(scst_cmd) ? 1 : 0;
|
||||
if (unlikely(req->tmfabort)) {
|
||||
req->tm_aborted |= scst_cmd_aborted(scst_cmd) ? 1 : 0;
|
||||
if (unlikely(req->tm_aborted)) {
|
||||
TRACE_MGMT_DBG("req %p (scst_cmd %p) aborted", req,
|
||||
req->scst_cmd);
|
||||
|
||||
scst_set_delivery_status(req->scst_cmd,
|
||||
SCST_CMD_DELIVERY_ABORTED);
|
||||
|
||||
if (old_state == ISCSI_CMD_STATE_RESTARTED) {
|
||||
req->scst_state = ISCSI_CMD_STATE_PROCESSED;
|
||||
req_cmnd_release_force(req, ISCSI_FORCE_RELEASE_WRITE);
|
||||
} else
|
||||
iscsi_set_state_wake_up(req, ISCSI_CMD_STATE_PROCESSED);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(old_state != ISCSI_CMD_STATE_RESTARTED)) {
|
||||
TRACE_DBG("req %p on %d state", req, old_state);
|
||||
|
||||
create_status_rsp(req, status, sense, sense_len);
|
||||
|
||||
switch(old_state) {
|
||||
case ISCSI_CMD_STATE_RX_CMD:
|
||||
case ISCSI_CMD_STATE_AFTER_PREPROC:
|
||||
@@ -2534,6 +2588,7 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
|
||||
default:
|
||||
sBUG();
|
||||
}
|
||||
|
||||
iscsi_set_state_wake_up(req, ISCSI_CMD_STATE_PROCESSED);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -230,6 +230,11 @@ typedef void (iscsi_show_info_t)(struct seq_file *seq, struct iscsi_target *targ
|
||||
#define ISCSI_CMD_STATE_RESTARTED 3 /* scst_restart_cmd() called and SCST processing it */
|
||||
#define ISCSI_CMD_STATE_PROCESSED 4 /* SCST done processing */
|
||||
|
||||
/* Command's reject reasons */
|
||||
#define ISCSI_REJECT_SCSI_CMD 1
|
||||
#define ISCSI_REJECT_CMD 2
|
||||
#define ISCSI_REJECT_DATA 3
|
||||
|
||||
/*
|
||||
* Most of the fields don't need any protection, since accessed from only a
|
||||
* single thread, except where noted.
|
||||
@@ -251,12 +256,14 @@ struct iscsi_cmnd {
|
||||
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 EXTRACHECKS
|
||||
unsigned int on_rx_digest_list:1;
|
||||
unsigned int release_called:1;
|
||||
#endif
|
||||
|
||||
unsigned long tmfabort; /* it's async. with the above flags */
|
||||
volatile unsigned int tm_aborted; /* it's async. with the above flags */
|
||||
|
||||
struct list_head hash_list_entry;
|
||||
|
||||
@@ -289,8 +296,6 @@ struct iscsi_cmnd {
|
||||
struct iscsi_cmnd *parent_req;
|
||||
struct iscsi_cmnd *cmd_req;
|
||||
|
||||
struct iscsi_target *target;
|
||||
|
||||
wait_queue_head_t scst_waitQ;
|
||||
int scst_state;
|
||||
struct scst_cmd *scst_cmd;
|
||||
@@ -316,10 +321,6 @@ struct iscsi_cmnd {
|
||||
struct list_head cmd_list_entry;
|
||||
};
|
||||
|
||||
#define ISCSI_OP_SCSI_REJECT ISCSI_OP_VENDOR1_CMD
|
||||
#define ISCSI_OP_PDU_REJECT ISCSI_OP_VENDOR2_CMD
|
||||
#define ISCSI_OP_DATA_REJECT ISCSI_OP_VENDOR3_CMD
|
||||
|
||||
/* Flags for req_cmnd_release_force() */
|
||||
#define ISCSI_FORCE_RELEASE_WRITE 1
|
||||
|
||||
|
||||
@@ -62,11 +62,6 @@ struct iscsi_hdr {
|
||||
#define ISCSI_OP_LOGOUT_CMD 0x06
|
||||
#define ISCSI_OP_SNACK_CMD 0x10
|
||||
|
||||
#define ISCSI_OP_VENDOR1_CMD 0x1c
|
||||
#define ISCSI_OP_VENDOR2_CMD 0x1d
|
||||
#define ISCSI_OP_VENDOR3_CMD 0x1e
|
||||
#define ISCSI_OP_VENDOR4_CMD 0x1f
|
||||
|
||||
/* Server to Client Message Opcode values */
|
||||
#define ISCSI_OP_NOOP_IN 0x20
|
||||
#define ISCSI_OP_SCSI_RSP 0x21
|
||||
|
||||
@@ -919,6 +919,8 @@ static void check_net_priv(struct iscsi_cmnd *cmd, struct page *page)
|
||||
}
|
||||
#else
|
||||
static inline void check_net_priv(struct iscsi_cmnd *cmd, struct page *page) {}
|
||||
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. */
|
||||
|
||||
@@ -697,6 +697,8 @@ static int q2t_xmit_response(struct scst_cmd *scst_cmd)
|
||||
"for aborted scst_cmd=%p (tag=%Ld)",
|
||||
ha->instance, scst_cmd, scst_cmd_get_tag(scst_cmd));
|
||||
|
||||
scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_ABORTED);
|
||||
|
||||
prm.cmd->state = Q2T_STATE_ABORTED;
|
||||
|
||||
q2t_send_term_exchange(ha, prm.cmd, &prm.cmd->atio, 0);
|
||||
|
||||
@@ -36,7 +36,6 @@ $ cp linux-2.6/build/*.ko /root/qla_isp
|
||||
|
||||
Each time you want to run qla_isp, unload all other qla modules
|
||||
|
||||
$ rmmod qla2x00tgt
|
||||
$ rmmod qla2x00tgt
|
||||
$ rmmod qla2400
|
||||
$ rmmod qla2300
|
||||
|
||||
@@ -1126,6 +1126,7 @@ isp_xmit_response(struct scst_cmd *scst_cmd)
|
||||
tmd_xact_t *xact = &tmd->cd_xact;
|
||||
|
||||
if (unlikely(scst_cmd_aborted(scst_cmd))) {
|
||||
scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_ABORTED);
|
||||
scst_tgt_cmd_done(scst_cmd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
+9
-2
@@ -349,8 +349,8 @@ or "Default" group, depending from either "Default_target_name" exists
|
||||
or not. In "Default_target_name" target name means name of the target.
|
||||
|
||||
In /proc/scsi_tgt each group represented as "groups/GROUP_NAME/"
|
||||
subdirectory. In it there are files "devices" and "users". File
|
||||
"devices" lists all devices and their LUNs in the group, file "users"
|
||||
subdirectory. In it there are files "devices" and "names". File
|
||||
"devices" lists all devices and their LUNs in the group, file "names"
|
||||
lists all names that should be bound to this group.
|
||||
|
||||
To configure access and devices visibility management SCST provides the
|
||||
@@ -790,6 +790,13 @@ limitations for Y value, it can be any value from 1 to possible maximum
|
||||
(usually, 32), so start from dividing the current value on 2, i.e. set
|
||||
16, if /sys/block/sdX/device/queue_depth contains 32.
|
||||
|
||||
Note, that logged messages about QUEUE_FULL status are quite different
|
||||
by nature. This is a normal work, just SCSI flow control in action.
|
||||
Simply don't enable "mgmt_minor" logging level, or, alternatively, if
|
||||
you are confident in the worst case performance of your back-end
|
||||
storage, you can increase SCST_MAX_TGT_DEV_COMMANDS in scst_priv.h to
|
||||
64. Usually initiators don't try to push more commands on the target.
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
|
||||
+3
-8
@@ -42,6 +42,8 @@
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
typedef _Bool bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
/* Version numbers, the same as for the kernel */
|
||||
@@ -373,7 +375,7 @@ typedef _Bool bool;
|
||||
#define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 10
|
||||
|
||||
#ifdef DEBUG_TM
|
||||
#define SCST_TGT_DEV_UNDER_TM_DBG 20
|
||||
#define SCST_TGT_DEV_UNDER_TM_DBG 20
|
||||
#endif
|
||||
|
||||
/*************************************************************
|
||||
@@ -2080,12 +2082,6 @@ static inline scst_data_direction scst_cmd_get_data_direction(
|
||||
return cmd->data_direction;
|
||||
}
|
||||
|
||||
/* Returns cmd's relative data offset */
|
||||
static inline unsigned int scst_cmd_get_offset(struct scst_cmd *cmd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns cmd's status byte from host device */
|
||||
static inline uint8_t scst_cmd_get_status(struct scst_cmd *cmd)
|
||||
{
|
||||
@@ -2208,7 +2204,6 @@ static inline void scst_cmd_set_tgt_sn(struct scst_cmd *cmd, uint32_t tgt_sn)
|
||||
cmd->tgt_sn = tgt_sn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns 1 if the cmd was aborted, so its status is invalid and no
|
||||
* reply shall be sent to the remote initiator. A target driver should
|
||||
|
||||
@@ -35,8 +35,9 @@
|
||||
** Allowed delivery statuses for cmd's delivery_status
|
||||
*************************************************************/
|
||||
|
||||
#define SCST_CMD_DELIVERY_SUCCESS 0
|
||||
#define SCST_CMD_DELIVERY_FAILED -1
|
||||
#define SCST_CMD_DELIVERY_SUCCESS 0
|
||||
#define SCST_CMD_DELIVERY_FAILED -1
|
||||
#define SCST_CMD_DELIVERY_ABORTED -2
|
||||
|
||||
/*************************************************************
|
||||
** Values for task management functions
|
||||
|
||||
@@ -1103,7 +1103,6 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = cmd->dev->handler->type; /* type dev */
|
||||
if ((buf[0] == TYPE_ROM) || virt_dev->removable)
|
||||
buf[1] = 0x80; /* removable */
|
||||
@@ -3352,7 +3351,7 @@ out_unreg:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void __exit exit_scst_vdisk(struct scst_dev_type *devtype,
|
||||
static void exit_scst_vdisk(struct scst_dev_type *devtype,
|
||||
struct list_head *vdisk_dev_list)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
+10
-16
@@ -3096,30 +3096,23 @@ void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd)
|
||||
/* It's completed and it's OK to return its result */
|
||||
goto out;
|
||||
}
|
||||
TRACE_MGMT_DBG("Flag ABORTED OTHER set for cmd %p (tag %llu)",
|
||||
cmd, cmd->tag);
|
||||
|
||||
if (cmd->dev->tas) {
|
||||
TRACE_MGMT_DBG("Flag ABORTED OTHER set for cmd %p "
|
||||
"(tag %llu), returning TASK ABORTED ", cmd,
|
||||
cmd->tag);
|
||||
scst_set_cmd_error_status(cmd, SAM_STAT_TASK_ABORTED);
|
||||
} else {
|
||||
TRACE_MGMT_DBG("Flag ABORTED OTHER set for cmd %p "
|
||||
"(tag %llu), aborting without delivery or "
|
||||
"notification", cmd, cmd->tag);
|
||||
/*
|
||||
* Abort without delivery or notification.
|
||||
* There is no need to check/requeue possible UA,
|
||||
* because, if it exists, it will be delivered
|
||||
* by the "completed" branch.
|
||||
* by the "completed" branch above.
|
||||
*/
|
||||
clear_bit(SCST_CMD_ABORTED_OTHER,
|
||||
&cmd->cmd_flags);
|
||||
clear_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
|
||||
}
|
||||
} else {
|
||||
if ((cmd->tgt_dev != NULL) &&
|
||||
scst_is_ua_sense(cmd->sense)) {
|
||||
/* This UA delivery is going to fail, so requeue it */
|
||||
TRACE_MGMT_DBG("Requeuing UA for aborted cmd %p", cmd);
|
||||
scst_check_set_UA(cmd->tgt_dev, cmd->sense,
|
||||
SCST_SENSE_BUFFERSIZE, 1);
|
||||
mempool_free(cmd->sense, scst_sense_mempool);
|
||||
cmd->sense = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -3402,6 +3395,7 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
|
||||
c, c->tag, tm_dbg_delayed_cmds_count);
|
||||
|
||||
if (!test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags)) {
|
||||
/* Test how completed commands handled */
|
||||
if (((scst_random() % 10) == 5)) {
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
|
||||
@@ -521,7 +521,7 @@ static int __init scst_proc_init_module_log(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void __exit scst_proc_cleanup_module_log(void)
|
||||
static void scst_proc_cleanup_module_log(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -702,7 +702,7 @@ out_nomem:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void __exit scst_proc_cleanup_groups(void)
|
||||
static void scst_proc_cleanup_groups(void)
|
||||
{
|
||||
struct scst_acg *acg_tmp, *acg;
|
||||
|
||||
|
||||
+14
-2
@@ -3502,20 +3502,32 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
||||
int other_ini, int call_dev_task_mgmt_fn)
|
||||
{
|
||||
unsigned long flags;
|
||||
static spinlock_t other_ini_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE(((mcmd != NULL) && (mcmd->fn == SCST_ABORT_TASK)) ? TRACE_MGMT_MINOR : TRACE_MGMT,
|
||||
"Aborting cmd %p (tag %llu, op %x)", cmd, cmd->tag, cmd->cdb[0]);
|
||||
|
||||
/* To protect from concurrent aborts */
|
||||
spin_lock_irqsave(&other_ini_lock, flags);
|
||||
|
||||
if (other_ini) {
|
||||
set_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
|
||||
smp_mb__after_set_bit();
|
||||
/* Might be necessary if command aborted several times */
|
||||
if (!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
set_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
|
||||
smp_mb__after_set_bit();
|
||||
}
|
||||
} else {
|
||||
/* Might be necessary if command aborted several times */
|
||||
clear_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
|
||||
}
|
||||
|
||||
set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
|
||||
spin_unlock_irqrestore(&other_ini_lock, flags);
|
||||
|
||||
|
||||
/*
|
||||
* To sync with cmd->finished/done set in
|
||||
* scst_finish_cmd()/scst_pre_xmit_response()
|
||||
|
||||
+4
-1
@@ -1821,8 +1821,10 @@ static int srpt_xmit_response(struct scst_cmd *scmnd)
|
||||
else if (ch->state == RDMA_CHANNEL_CONNECTING)
|
||||
ret = SCST_TGT_RES_QUEUE_FULL;
|
||||
|
||||
if (unlikely(scst_cmd_aborted(scmnd)))
|
||||
if (unlikely(scst_cmd_aborted(scmnd))) {
|
||||
scst_set_delivery_status(scmnd, SCST_CMD_DELIVERY_ABORTED);
|
||||
ret = SCST_TGT_RES_SUCCESS;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
@@ -1836,6 +1838,7 @@ static int srpt_xmit_response(struct scst_cmd *scmnd)
|
||||
printk(KERN_ERR PFX
|
||||
"%s[%d] tag= %lld already get aborted\n",
|
||||
__FUNCTION__, __LINE__, (unsigned long long)tag);
|
||||
scst_set_delivery_status(ioctx->scmnd, SCST_CMD_DELIVERY_ABORTED);
|
||||
scst_tgt_cmd_done(ioctx->scmnd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user