- Rejecting command reimplemented in a more simple, straightforward and readable...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 7 May 2008 18:44:15 +0000 (18:44 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 7 May 2008 18:44:15 +0000 (18:44 +0000)
 - 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: https://scst.svn.sourceforge.net/svnroot/scst/trunk@364 d57e44dd-8a1f-0410-8b47-8ef2f437770f

16 files changed:
iscsi-scst/kernel/digest.c
iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/iscsi_hdr.h
iscsi-scst/kernel/nthread.c
qla2x00t/qla2x00-target/qla2x00t.c
qla_isp/README.scst
qla_isp/linux/isp_scst.c
scst/README
scst/include/scst.h
scst/include/scst_const.h
scst/src/dev_handlers/scst_vdisk.c
scst/src/scst_lib.c
scst/src/scst_proc.c
scst/src/scst_targ.c
srpt/src/ib_srpt.c

index 1ba39c0..fea0dd5 100644 (file)
@@ -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;
index ee771bc..72bf9a3 100644 (file)
@@ -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;
        }
index ee61e92..e0368e1 100644 (file)
@@ -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
 
index 99f694d..335ca88 100644 (file)
@@ -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
index 23102c1..3a6e051 100644 (file)
@@ -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. */
index e959e1f..000318a 100644 (file)
@@ -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);
index 5f4ce52..4e7358d 100644 (file)
@@ -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
index edd675f..7285475 100644 (file)
@@ -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);
     }
index 75ca05f..8b93b55 100644 (file)
@@ -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
 -------
 
index 555a077..5dc3d42 100644 (file)
@@ -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
index 4f6abee..a499760 100644 (file)
@@ -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
index df3595c..46aba9a 100644 (file)
@@ -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();
index 037e90a..53681e1 100644 (file)
@@ -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));
index b92fc56..4a1ffdd 100644 (file)
@@ -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;
 
index 8c47cb7..1e20592 100644 (file)
@@ -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()
index 73a45dc..2d288f9 100644 (file)
@@ -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;
        }