Simple bugfix for concurrent work of several targets, which eventually turned out...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 7 Dec 2007 17:00:42 +0000 (17:00 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 7 Dec 2007 17:00:42 +0000 (17:00 +0000)
Particularly:
 - Added ability for target drivers to set result of command's status delvery to initiator (see scst_set_delivery_status())
 - Added ability for user space devices set some mode page parameters to make SCST core behave correspondingly
 - TM improvements
 - Few possible crashes fixed
 - Logging improvements
 - Performance improvements
 - Docs updates

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@227 d57e44dd-8a1f-0410-8b47-8ef2f437770f

31 files changed:
doc/scst_user_spec.txt
iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi_dbg.h
iscsi-scst/kernel/nthread.c
mpt/mpt_scst.c
qla2x00t/qla2x00-target/qla2x00t.c
qla_isp/linux/isp_scst.c
scst/README
scst/include/scsi_tgt.h
scst/include/scst_const.h
scst/include/scst_debug.h
scst/include/scst_user.h
scst/src/dev_handlers/scst_cdrom.c
scst/src/dev_handlers/scst_changer.c
scst/src/dev_handlers/scst_dev_handler.h
scst/src/dev_handlers/scst_disk.c
scst/src/dev_handlers/scst_modisk.c
scst/src/dev_handlers/scst_processor.c
scst/src/dev_handlers/scst_raid.c
scst/src/dev_handlers/scst_tape.c
scst/src/dev_handlers/scst_user.c
scst/src/dev_handlers/scst_vdisk.c
scst/src/scst_lib.c
scst/src/scst_main.c
scst/src/scst_priv.h
scst/src/scst_proc.c
scst/src/scst_targ.c
usr/fileio/common.c
usr/fileio/common.h
usr/fileio/debug.h
usr/fileio/fileio.c

index 86b628b..2b89390 100644 (file)
@@ -2,7 +2,7 @@
 
          USER SPACE INTERFACE DESCRIPTION.
 
-                  Version 0.9.6/1
+                  Version 0.9.6/2
 
 
                I. Description.
@@ -62,6 +62,7 @@ struct scst_user_dev_desc
 {
        uint8_t version;
        uint8_t type;
+       uint8_t has_own_order_mgmt;
        struct scst_user_opt opt;
        uint32_t block_size;
        char name[SCST_MAX_NAME];
@@ -73,6 +74,10 @@ where:
 
  - type - SCSI type of the device
 
+ - has_own_order_mgmt - set it in non-zero, if device implements own
+   ORDERED commands management, i.e. guarantees commands execution order
+   requirements, specified by SAM.
+
  - opt - device options, see SCST_USER_SET_OPTIONS/SCST_USER_GET_OPTIONS below
 
  - block_size - block size, shall be divisible by 512 for block devices
@@ -101,6 +106,11 @@ struct scst_user_opt
        uint8_t prio_queue_type;
        uint8_t partial_transfers_type;
        uint32_t partial_len;
+
+       uint8_t tst;
+       uint8_t queue_alg;
+       uint8_t tas;
+       uint8_t swp;
 },
 
 where:
@@ -181,6 +191,9 @@ where:
    * SCST_USER_PARTIAL_TRANSFERS_SUPPORTED - the partial data transfers
      are supported without limitations.
 
+ - tst, queue_alg, tas and swp - set values for TST, QUEUE ALGORITHM MODIFIER,
+   TAS and SWP fields from control mode page correspondingly, see SPC.
+
 Flags parse_type and on_free_cmd_type are designed to improve
 performance by eliminating context switches to the user space handler,
 when processing of the corresponding events isn't needed.
@@ -572,6 +585,7 @@ struct scst_user_scsi_on_free_cmd
        uint8_t buffer_cached;
        uint8_t aborted;
        uint8_t status;
+       uint8_t delivery_status;
 },
 
 where:
@@ -586,7 +600,14 @@ where:
  - aborted - true, if command was aborted
 
  - status - SAM status of the commands execution
+
+ - delivery_status - status of cmd's status/data delivery to remote
+   initiator. Can be:
    
+   * SCST_CMD_DELIVERY_SUCCESS - delivery succeeded
+
+   * SCST_CMD_DELIVERY_FAILED - delivery failed
+
 The user space handler should reply using the corresponding reply
 command. No error code is needed.
 
index 1a23679..b21994d 100644 (file)
@@ -721,7 +721,8 @@ static struct iscsi_cmnd *cmnd_find_hash_get(struct iscsi_session *session,
 
        spin_lock(&session->cmnd_hash_lock);
        cmnd = __cmnd_find_hash(session, itt, ttt);
-       cmnd_get(cmnd);
+       if (cmnd)
+               cmnd_get(cmnd);
        spin_unlock(&session->cmnd_hash_lock);
 
        return cmnd;
@@ -1296,7 +1297,7 @@ static int data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
        cmnd->cmd_req = req = cmnd_find_hash(conn->session, req_hdr->itt,
                                        req_hdr->ttt);
        if (!req) {
-               PRINT_ERROR("unable to find scsi task %x %x",
+               PRINT_ERROR("Unable to find scsi task %x %x",
                        cmnd_itt(cmnd), cmnd_ttt(cmnd));
                goto skip_pdu;
        }
@@ -1583,7 +1584,8 @@ static void execute_task_management(struct iscsi_cmnd *req)
        int err = 0, function = req_hdr->function & ISCSI_FUNCTION_MASK;
        struct scst_rx_mgmt_params params;
 
-       TRACE(TRACE_MGMT, "TM cmd: req %p, itt %x, fn %d, rtt %x", req, cmnd_itt(req),
+       TRACE((function == ISCSI_FUNCTION_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
+               "TM cmd: req %p, itt %x, fn %d, rtt %x", req, cmnd_itt(req),
                function, req_hdr->rtt);
 
        memset(&params, 0, sizeof(params));
@@ -2318,7 +2320,9 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status)
                                (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
        struct iscsi_task_rsp_hdr *rsp_hdr;
 
-       TRACE(TRACE_MGMT, "TM req %p finished, status %d", req, status);
+       TRACE((req_hdr->function == ISCSI_FUNCTION_ABORT_TASK) ?
+                        TRACE_MGMT_MINOR : TRACE_MGMT,
+               "TM req %p finished, status %d", req, status);
 
        rsp = iscsi_cmnd_create_rsp_cmnd(req);
        rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs;
index 4df5e89..874c697 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifdef DEBUG
 #define ISCSI_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_LINE | TRACE_PID | \
-       TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \
+       TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | TRACE_MGMT_DEBUG | \
        TRACE_MINOR | TRACE_SPECIAL | TRACE_CONN_OC)
 #else
 #define ISCSI_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
index 2a55abe..6b38c14 100644 (file)
@@ -817,6 +817,9 @@ err:
                        (unsigned long long)conn->session->sid, conn->cid,
                        conn->write_cmnd);
        }
+       if (ref_cmd->scst_cmd != NULL)
+               scst_set_delivery_status(ref_cmd->scst_cmd,
+                       SCST_CMD_DELIVERY_FAILED);
        return res;
 }
 
index 9dde44e..b0ebdfc 100644 (file)
@@ -65,8 +65,8 @@ static char *mpt_state_string[] = {
 
 #ifdef DEBUG
 #define SCST_DEFAULT_MPT_LOG_FLAGS (TRACE_FUNCTION | TRACE_PID | \
-        TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \
-        TRACE_MINOR | TRACE_SPECIAL)
+        TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | \
+        TRACE_MGMT_DEBUG | TRACE_MINOR | TRACE_SPECIAL)
 #else
 # ifdef TRACING
 #define SCST_DEFAULT_MPT_LOG_FLAGS (TRACE_FUNCTION | TRACE_PID | \
@@ -803,6 +803,7 @@ stm_tgt_reply(MPT_ADAPTER *ioc, u32 reply_word)
                                case MPT_STATUS_SENSE_ATTEMPT:
                                        atomic_set(&priv->pending_sense[init_index], 
                                                MPT_STATUS_SENSE_IDLE);
+                                       /* ToDo: check and set scst_set_delivery_status(), if necessary */
                                        scst_tgt_cmd_done(scst_cmd);
                                        break;
 
@@ -813,6 +814,7 @@ stm_tgt_reply(MPT_ADAPTER *ioc, u32 reply_word)
                                case MPT_STATUS_SENSE_NOT_SENT:
                                        atomic_set(&priv->pending_sense[init_index], 
                                                MPT_STATUS_SENSE_HANDLE_RQ);
+                                       /* ToDo: check and set scst_set_delivery_status(), if necessary */
                                        scst_tgt_cmd_done(scst_cmd);
                                        break;
 
@@ -831,10 +833,12 @@ stm_tgt_reply(MPT_ADAPTER *ioc, u32 reply_word)
                                default:
                                        /* nothing much to do here, we aren't 
                                         * handling cached sense/status */
+                                       /* ToDo: check and set scst_set_delivery_status(), if necessary */
                                        scst_tgt_cmd_done(scst_cmd);
                                        break;
                        }
                } else {
+                       /* ToDo: check and set scst_set_delivery_status(), if necessary */
                        scst_tgt_cmd_done(scst_cmd);
                }
 
@@ -1674,6 +1678,7 @@ mpt_xmit_response(struct scst_cmd *scst_cmd)
        return res;
 
  out_tgt_free:
+       /* ToDo: check and set scst_set_delivery_status(), if necessary */
        scst_tgt_cmd_done(scst_cmd);
        goto out;
 }
index e375a1b..118490b 100644 (file)
@@ -49,8 +49,8 @@
 
 #ifdef DEBUG
 #define Q2T_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_PID | \
-       TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \
-       TRACE_MINOR | TRACE_SPECIAL)
+       TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | \
+       TRACE_MGMT_DEBUG | TRACE_MINOR | TRACE_SPECIAL)
 #else
 # ifdef TRACING
 #define Q2T_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MINOR | \
@@ -689,7 +689,7 @@ static int q2t_xmit_response(struct scst_cmd *scst_cmd)
        if (unlikely(scst_cmd_aborted(scst_cmd))) {
                scsi_qla_host_t *ha = sess->tgt->ha;
 
-               TRACE(TRACE_MGMT, "qla2x00tgt(%ld): terminating exchange "
+               TRACE(TRACE_MGMT_MINOR, "qla2x00tgt(%ld): terminating exchange "
                        "for aborted scst_cmd=%p (tag=%Ld)",
                        ha->instance, scst_cmd, scst_cmd_get_tag(scst_cmd));
 
@@ -1004,13 +1004,13 @@ static void q2t_do_ctio_completion(scsi_qla_host_t *ha,
        handle &= ~CTIO_COMPLETION_HANDLE_MARK;
 
        if (status != CTIO_SUCCESS) {
+               err = 1;
                switch (status) {
                case CTIO_LIP_RESET:
                case CTIO_TARGET_RESET:
                case CTIO_ABORTED:
                case CTIO_TIMEOUT:
                case CTIO_INVALID_RX_ID:
-                       err = 1;
                        /* they are OK */
                        TRACE_MGMT_DBG("qla2x00tgt(%ld): CTIO with status %#x "
                                "received (LIP_RESET=e, ABORTED=2, "
@@ -1020,14 +1020,12 @@ static void q2t_do_ctio_completion(scsi_qla_host_t *ha,
 
                case CTIO_PORT_LOGGED_OUT:
                case CTIO_PORT_UNAVAILABLE:
-                       err = 1;
                        PRINT_INFO("qla2x00tgt(%ld): CTIO with PORT LOGGED "
                                "OUT (29) or PORT UNAVAILABLE (28) status %x "
                                "received", ha->instance, status);
                        break;
 
                default:
-                       err = 1;
                        PRINT_ERROR("qla2x00tgt(%ld): CTIO with error status "
                                    "0x%x received", ha->instance, status);
                        break;
@@ -1133,6 +1131,7 @@ out:
 out_free:
        if (unlikely(err)) {
                TRACE_MGMT_DBG("%s", "Finishing failed CTIO");
+               scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_FAILED);
        }
        scst_tgt_cmd_done(scst_cmd);
        goto out;
@@ -1360,7 +1359,6 @@ static int q2t_send_cmd_to_scst(scsi_qla_host_t *ha, atio_entry_t *atio)
        /*        le64_to_cpu(*(uint64_t *)(((char *)atio)+0x2c))); */
        /*le32_to_cpu(*(uint32_t *)atio->initiator_port_name)); */
 
-
        if (tgt->tgt_shutdown) {
                TRACE_MGMT_DBG("New command while device %p is shutting "
                        "down", tgt);
@@ -1606,8 +1604,9 @@ static void q2t_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
 
        TRACE_ENTRY();
 
-       TRACE(TRACE_MGMT, "scst_mcmd (%p) status %#x state %#x", scst_mcmd, 
-             scst_mcmd->status, scst_mcmd->state);
+       TRACE((scst_mcmd->fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
+               "scst_mcmd (%p) status %#x state %#x", scst_mcmd,
+               scst_mcmd->status, scst_mcmd->state);
 
        mcmd = scst_mgmt_cmd_get_tgt_priv(scst_mcmd);
        if (unlikely(mcmd == NULL)) {
@@ -1671,7 +1670,7 @@ static void q2t_handle_imm_notify(scsi_qla_host_t *ha, notify_entry_t *iocb)
                break;
 
        case IMM_NTFY_ABORT_TASK:
-               TRACE(TRACE_MGMT, "Abort Task (S %04x I %#x -> L %#x)", 
+               TRACE(TRACE_MGMT_MINOR, "Abort Task (S %04x I %#x -> L %#x)", 
                      le16_to_cpu(iocb->seq_id), loop_id,
                      le16_to_cpu(iocb->lun));
                if (q2t_abort_task(ha, iocb) == 0)
index fcbb5fa..a565c01 100644 (file)
@@ -547,6 +547,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
             xfr->td_hflags &= ~TDFH_DATA_MASK;
             xfr->td_xfrlen = 0;
         }
+        /* ToDo: check and set scst_set_delivery_status(), if necessary */
         scst_tgt_cmd_done(scst_cmd);
         return;
     }
@@ -561,6 +562,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
                 }
                 scst_rx_data(scst_cmd, SCST_RX_STATUS_SUCCESS, SCST_CONTEXT_TASKLET);
             } else {
+               /* ToDo: check and set scst_set_delivery_status(), if necessary */
                 scst_tgt_cmd_done(scst_cmd);
             }
         } else {
@@ -569,6 +571,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
     } else if (xfr->td_hflags & TDFH_DATA_IN) {
         xfr->td_hflags &= ~TDFH_DATA_MASK;
         xfr->td_xfrlen = 0;
+        /* ToDo: check and set scst_set_delivery_status(), if necessary */
         scst_tgt_cmd_done(scst_cmd);
     }
 }
index 4dbd41a..07e4db3 100644 (file)
@@ -465,9 +465,19 @@ IMPORTANT: By default for performance reasons VDISK FILEIO devices use write
           usually it turned off by default and the status of barriers
           usage isn't reported anywhere in the system logs as well as
           there is no way to know it on the mounted file system (at
-          least no known one). Also note that on some real-life
-          workloads write through caching might perform better, than
-          write back one with the barrier protection turned on.
+          least no known one). Windows and, AFAIK, other UNIX'es don't
+          need any special explicit options and do necessary barrier
+          actions on write-back caching devices by default. Also note
+          that on some real-life workloads write through caching might
+          perform better, than write back one with the barrier
+          protection turned on.
+          Also you should realize that Linux doesn't provide a
+          guarantee that after sync()/fsync() all written data really
+          hit permanent storage, they can be then in the cache of your
+          backstorage device and lost on power failure event. Thus,
+          ever with write-through cache mode, you still need a good UPS
+          to protect yourself from your data loss (note, data loss, not
+          the file system integrity).
 
 IMPORTANT: Some disk and partition table management utilities don't support
 =========  block sizes >512 bytes, therefore make sure that your favorite one
@@ -598,10 +608,10 @@ If you use SCST version taken directly from the SVN repository, you can
 set the above options, except ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ, using
 debug2perf Makefile target.
 
-4. For kernel:
+4. For other target and initiator software parts:
 
- - Don't enable debug/hacking features, i.e. use them as they are by
-   default.
+ - Don't enable debug/hacking features in the kernel, i.e. use them as
+   they are by default.
 
  - The default kernel read-ahead and queuing settings are optimized
    for locally attached disks, therefore they are not optimal if they
@@ -639,23 +649,31 @@ debug2perf Makefile target.
    directory, they also affect performance. If you find the best values,
    please share them with us.
 
- - Use on the target deadline IO scheduler with read_expire and
-   write_expire increased on all exported devices to 5000 and 20000
-   correspondingly.
+ - On the target deadline IO scheduler with read_expire and
+   write_expire increased on all exported devices to 5000 and 15000
+   correspondingly used to be the fastest, but currently seems CFQ often
+   outperforms it. So, try on your load and use the best one.
 
  - It is recommended to turn the kernel preemption off, i.e. set
    the kernel preemption model to "No Forced Preemption (Server)".
 
-5. For hardware.
-
- - Make sure that your target hardware (e.g. target FC card) and underlaying
-   IO hardware (e.g. IO card, like SATA, SCSI or RAID to which your
-   disks connected) stay on different PCI buses. They have to work in
-   parallel, so it will be better if they don't compete for the bus. The
-   problem is not only in the bandwidth, which they have to share, but
-   also in the interaction between cards during that competition. In
-   some cases it could lead up to 5-10 times less performance, than
-   expected.
+ - Looks like XFS is the best filesystem on the target to store device
+   files, because it allows considerably better linear write throughput,
+   than ext3.
+
+5. For hardware on target.
+
+ - Make sure that your target hardware (e.g. target FC or network card)
+   and underlaying IO hardware (e.g. IO card, like SATA, SCSI or RAID to
+   which your disks connected) don't share the same PCI bus. They have
+   to work in parallel, so it will be better if they don't compete for
+   the bus. The problem is not only in the bandwidth, which they have to
+   share, but also in the interaction between cards during that
+   competition. This is very important, because in some cases if target
+   and backend storage controllers share the same PCI bus, it could lead
+   up to 5-10 times less performance, than expected. If you have no
+   choice, but PCI bus sharing, set in the BIOS PCI latency as low as
+   possible.
 
 IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
 =========  you can't get good write performance for VDISK FILEIO devices with
index f801a7a..73be939 100644 (file)
 /* Version numbers, the same as for the kernel */
 #define SCST_VERSION_CODE 0x000906
 #define SCST_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-#define SCST_VERSION_STRING "0.9.6-pre3"
+#define SCST_VERSION_STRING "0.9.6-rc1"
 
 /*************************************************************
- ** States of command processing state machine
+ ** States of command processing state machine. At first, 
+ ** "active" states, then - "passive" ones. This is to have
+ ** more efficient generated code of the corresponding
+ ** "switch" statements.
  *************************************************************/
 
-/* A cmd is created, but scst_cmd_init_done() not called */
-#define SCST_CMD_STATE_INIT_WAIT     1
-
-/* LUN translation (cmd->tgt_dev assignment) */
-#define SCST_CMD_STATE_INIT          2
+/* Internal parsing */
+#define SCST_CMD_STATE_PRE_PARSE     0
 
 /* Dev handler's parse() is going to be called */
-#define SCST_CMD_STATE_DEV_PARSE     4
-
-/* Allocation of the cmd's data buffer */
-#define SCST_CMD_STATE_PREPARE_SPACE 5
+#define SCST_CMD_STATE_DEV_PARSE     1
 
 /* Allocation of the cmd's data buffer */
-#define SCST_CMD_STATE_PREPROCESS_DONE 6
+#define SCST_CMD_STATE_PREPARE_SPACE 2
 
 /* Target driver's rdy_to_xfer() is going to be called */
-#define SCST_CMD_STATE_RDY_TO_XFER   7
-
-/* Waiting for data from the initiator (until scst_rx_data() called) */
-#define SCST_CMD_STATE_DATA_WAIT     8
+#define SCST_CMD_STATE_RDY_TO_XFER   3
 
 /* Target driver's pre_exec() is going to be called */
-#define SCST_CMD_STATE_PRE_EXEC      9
+#define SCST_CMD_STATE_TGT_PRE_EXEC  4
 
 /* CDB is going to be sent to SCSI mid-level for execution */
-#define SCST_CMD_STATE_SEND_TO_MIDLEV 10
+#define SCST_CMD_STATE_SEND_TO_MIDLEV 5
 
-/* Waiting for CDB's execution finish */
-#define SCST_CMD_STATE_EXECUTING     11
+/* Internal pos-exec checks */
+#define SCST_CMD_STATE_PRE_DEV_DONE  6
+
+/* Internal MODE SELECT pages related checks */
+#define SCST_CMD_STATE_MODE_SELECT_CHECKS 7
 
 /* Dev handler's dev_done() is going to be called */
-#define SCST_CMD_STATE_DEV_DONE      12
+#define SCST_CMD_STATE_DEV_DONE      8
 
 /* Target driver's xmit_response() is going to be called */
-#define SCST_CMD_STATE_XMIT_RESP     13
+#define SCST_CMD_STATE_PRE_XMIT_RESP 9
 
-/* Waiting for response's transmission finish */
-#define SCST_CMD_STATE_XMIT_WAIT     14
+/* Target driver's xmit_response() is going to be called */
+#define SCST_CMD_STATE_XMIT_RESP     10
 
 /* The cmd finished */
-#define SCST_CMD_STATE_FINISHED      15
+#define SCST_CMD_STATE_FINISHED      11
+
+#define SCST_CMD_STATE_LAST_ACTIVE   (SCST_CMD_STATE_FINISHED+100)
+
+
+/* A cmd is created, but scst_cmd_init_done() not called */
+#define SCST_CMD_STATE_INIT_WAIT     (SCST_CMD_STATE_LAST_ACTIVE+1)
+
+/* LUN translation (cmd->tgt_dev assignment) */
+#define SCST_CMD_STATE_INIT          (SCST_CMD_STATE_LAST_ACTIVE+2)
+
+/* Allocation of the cmd's data buffer */
+#define SCST_CMD_STATE_PREPROCESS_DONE (SCST_CMD_STATE_LAST_ACTIVE+3)
+
+/* Waiting for data from the initiator (until scst_rx_data() called) */
+#define SCST_CMD_STATE_DATA_WAIT     (SCST_CMD_STATE_LAST_ACTIVE+4)
+
+/* Waiting for CDB's execution finish */
+#define SCST_CMD_STATE_EXECUTING     (SCST_CMD_STATE_LAST_ACTIVE+5)
+
+/* Waiting for response's transmission finish */
+#define SCST_CMD_STATE_XMIT_WAIT     (SCST_CMD_STATE_LAST_ACTIVE+6)
 
 /************************************************************* 
- ** Can be retuned instead of cmd's state by dev handlers' 
- ** functions, if the command's state should be set by default
+ * Can be retuned instead of cmd's state by dev handlers' 
+ * functions, if the command's state should be set by default
  *************************************************************/
-#define SCST_CMD_STATE_DEFAULT       0
+#define SCST_CMD_STATE_DEFAULT        500
 
 /************************************************************* 
- ** Can be retuned instead of cmd's state by dev handlers' 
- ** functions, if it is impossible to complete requested
- ** task in atomic context. The cmd will be restarted in thread 
- ** context.
+ * Can be retuned instead of cmd's state by dev handlers' 
+ * functions, if it is impossible to complete requested
+ * task in atomic context. The cmd will be restarted in thread 
+ * context.
  *************************************************************/
-#define SCST_CMD_STATE_NEED_THREAD_CTX       100
+#define SCST_CMD_STATE_NEED_THREAD_CTX 1000
 
 /************************************************************* 
- ** Can be retuned instead of cmd's state by dev handlers' 
- ** parse function, if the cmd processing should be stopped
- ** for now. The cmd will be restarted by dev handlers itself.
+ * Can be retuned instead of cmd's state by dev handlers' 
+ * parse function, if the cmd processing should be stopped
+ * for now. The cmd will be restarted by dev handlers itself.
  *************************************************************/
-#define SCST_CMD_STATE_STOP          101
+#define SCST_CMD_STATE_STOP           1001
 
 /*************************************************************
  ** States of mgmt command processing state machine
  */
 #define SCST_PREPROCESS_STATUS_ERROR_FATAL   3
 
+/* Thread context requested */
+#define SCST_PREPROCESS_STATUS_NEED_THREAD   4
+
 /*************************************************************
  ** Allowed return codes for xmit_response(), rdy_to_xfer(), 
  ** report_aen() 
 /* Set if no response should be sent to the target about this cmd */
 #define SCST_CMD_NO_RESP               2
 
-/*
- * Set if the cmd is being executed. Needed to guarantee that 
- * "no further responses from the task are sent to
- * the SCSI initiator port" after response from the TM function is 
- * sent (SAM) as well as correct ABORT TASK status code
- */
-#define SCST_CMD_EXECUTING             3
-
-/*
- * Set if the cmd status/data are being xmitted. The purpose is the
- * same as for SCST_CMD_EXECUTING
- */
-#define SCST_CMD_XMITTING              4
-
 /* Set if the cmd is dead and can be destroyed at any time */
-#define SCST_CMD_CAN_BE_DESTROYED      5
+#define SCST_CMD_CAN_BE_DESTROYED      3
 
 /*************************************************************
  ** Tgt_dev's flags (tgt_dev_flags)
@@ -664,9 +671,6 @@ struct scst_dev_type
        /* Set, if no /proc files should be automatically created by SCST */
        unsigned no_proc:1;
 
-       /* Set if increment expected_sn in cmd->scst_cmd_done() */
-       unsigned inc_expected_sn_on_done:1; 
-
        /* 
         * Called to parse CDB from the cmd and initialize 
         * cmd->bufflen and cmd->data_direction (both - REQUIRED).
@@ -964,6 +968,9 @@ struct scst_cmd
         */
        unsigned int sent_to_midlev:1;
 
+       /* Set if scst_local_exec() was already called for this cmd */
+       unsigned int local_exec_done:1;
+
        /* Set if the cmd's action is completed */
        unsigned int completed:1;
 
@@ -1058,9 +1065,6 @@ struct scst_cmd
        /* Set if the cmd is deferred HEAD OF QUEUE */
        unsigned int hq_deferred:1;
 
-       /* Set if the internal parse should be skipped */
-       unsigned int skip_parse:1;
-
        /*
         * Set if increment expected_sn in cmd->scst_cmd_done() (to save
         * extra dereferences)
@@ -1074,14 +1078,17 @@ struct scst_cmd
 
        unsigned long cmd_flags; /* cmd's async flags */
 
+       /* Keeps status of cmd's status/data delivery to remote initiator */
+       int delivery_status;
+
        struct scst_tgt_template *tgtt; /* to save extra dereferences */
        struct scst_tgt *tgt;           /* to save extra dereferences */
        struct scst_device *dev;        /* to save extra dereferences */
 
-       lun_t lun;                      /* LUN for this cmd */
-
        struct scst_tgt_dev *tgt_dev;   /* corresponding device for this cmd */
 
+       lun_t lun;                      /* LUN for this cmd */
+
        /* The corresponding mgmt cmd, if any, protected by sess_list_lock */
        struct scst_mgmt_cmd *mgmt_cmnd;
 
@@ -1276,6 +1283,26 @@ struct scst_device
 
        /**************************************************************/
 
+       /*************************************************************
+        ** Dev's control mode page related values. Updates serialized
+        ** by scst_block_dev(). It's long to not interfere with the
+        ** above flags.
+        *************************************************************/
+
+       unsigned long queue_alg:4;
+       unsigned long tst:3;
+       unsigned long tas:1;
+       unsigned long swp:1;
+
+       /*
+        * Set if device implements own ordered commands management.
+        * Particularly, if set, expected_sn will be incremented immediately
+        * after exec() returned.
+        */
+       unsigned long has_own_order_mgmt:1; 
+
+       /**************************************************************/
+
        spinlock_t dev_lock;            /* device lock */
 
        /* 
@@ -1304,8 +1331,8 @@ struct scst_device
        /* Used to wait for requested amount of "on_dev" commands */
        wait_queue_head_t on_dev_waitQ;
 
-       /* A list entry used during RESETs, protected by scst_mutex */
-       struct list_head reset_dev_list_entry;
+       /* A list entry used during TM, protected by scst_mutex */
+       struct list_head tm_dev_list_entry;
 
        /* Virtual device internal ID */
        int virt_id;
@@ -1411,8 +1438,6 @@ struct scst_tgt_dev
        
        /* internal tmp list entry */
        struct list_head extra_tgt_dev_list_entry;
-
-       
 };
 
 /*
@@ -1692,7 +1717,9 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context);
 
 /* 
  * Notifies SCST that the driver sent the response and the command
- * can be freed now.
+ * can be freed now. Don't forget to set the delivery status, if it
+ * isn't success, using scst_set_delivery_status() before calling
+ * this function.
  */
 void scst_tgt_cmd_done(struct scst_cmd *cmd);
 
@@ -2134,6 +2161,22 @@ static inline void scst_clear_may_need_dma_sync(struct scst_cmd *cmd)
        cmd->may_need_dma_sync = 0;
 }
 
+/*
+ * Get/clear functions for cmd's delivery_status. It is one of
+ * SCST_CMD_DELIVERY_* constants, it specifies the status of the
+ * command's delivery to initiator.
+ */
+static inline int scst_get_delivery_status(struct scst_cmd *cmd)
+{
+       return cmd->delivery_status;
+}
+
+static inline void scst_set_delivery_status(struct scst_cmd *cmd,
+       int delivery_status)
+{
+       cmd->delivery_status = delivery_status;
+}
+
 /*
  * Get/Set function for mgmt cmd's target private data
  */
@@ -2314,6 +2357,9 @@ struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry * root,
 int scst_add_cmd_threads(int num);
 void scst_del_cmd_threads(int num);
 
+void scst_set_sense(uint8_t *buffer, int len, int key,
+       int asc, int ascq);
+
 void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense, 
        unsigned int len);
 
@@ -2334,7 +2380,7 @@ void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len);
  * Checks if total memory allocated by commands is less, than defined
  * limit (scst_cur_max_cmd_mem) and returns 0, if it is so. Otherwise,
  * returnes 1 and sets on cmd QUEUE FULL or BUSY status as well as
- * SCST_CMD_STATE_XMIT_RESP state. Target drivers and dev handlers are
+ * SCST_CMD_STATE_PRE_XMIT_RESP state. Target drivers and dev handlers are
  * required to call this function if they allocate data buffers on their
  * own.
  */
index 218fa74..24288c6 100644 (file)
@@ -3,7 +3,7 @@
  *  
  *  Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
  *  
- *  Contains macroses for execution tracing and error reporting
+ *  Contains common SCST constants.
  * 
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
 /* Max size of sense */
 #define SCST_SENSE_BUFFERSIZE        96
 
+/*************************************************************
+ ** Allowed delivery statuses for cmd's delivery_status
+ *************************************************************/
+
+#define SCST_CMD_DELIVERY_SUCCESS        0
+#define SCST_CMD_DELIVERY_FAILED        -1
+
 /************************************************************* 
  ** Values for task management functions
  *************************************************************/
@@ -48,7 +55,7 @@
  */
 #define SCST_NEXUS_LOSS_SESS         6
 
-/* Aborts all tasks in the corresponding session with TASK_ABORTED status */
+/* Aborts all tasks in the corresponding session */
 #define SCST_ABORT_ALL_TASKS_SESS    7
 
 /* 
@@ -58,7 +65,7 @@
  */
 #define SCST_NEXUS_LOSS              8
 
-/* Aborts all tasks in all sessions of the tgt with TASK_ABORTED status */
+/* Aborts all tasks in all sessions of the tgt */
 #define SCST_ABORT_ALL_TASKS         9
 
 /************************************************************* 
@@ -100,6 +107,11 @@ enum scst_cmd_queue_type
 
 #define SCST_NO_SENSE(sense)         (((uint8_t *)(sense))[2] == 0)
 
+static inline int scst_is_ua_sense(const uint8_t *sense)
+{
+       return SCST_SENSE_VALID(sense) && (sense[2] == UNIT_ATTENTION);
+}
+
 /*************************************************************
  ** Sense data for the appropriate errors. Can be used with
  ** scst_set_cmd_error()
@@ -122,6 +134,9 @@ enum scst_cmd_queue_type
 #define scst_sense_write_error                 MEDIUM_ERROR,    0x03, 0
 #define scst_sense_not_ready                   NOT_READY,       0x04, 0x10
 #define scst_sense_invalid_message             ILLEGAL_REQUEST, 0x49, 0
+#define scst_sense_cleared_by_another_ini_UA   UNIT_ATTENTION,  0x2F, 0
+
+#define SCST_STANDARD_SENSE_LEN                        14
 
 /************************************************************* 
  * SCSI opcodes not listed anywhere else
@@ -231,6 +246,18 @@ enum scst_cmd_queue_type
 #define LONG_BIT                     2
 #define BT_BIT                       1
 
+/*************************************************************
+ ** Values for the control mode page TST field
+ *************************************************************/
+#define SCST_CONTR_MODE_ONE_TASK_SET  0
+#define SCST_CONTR_MODE_SEP_TASK_SETS 1
+
+/*******************************************************************
+ ** Values for the control mode page QUEUE ALGORITHM MODIFIER field
+ *******************************************************************/
+#define SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER   0
+#define SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER 1
+
 /************************************************************* 
  ** Misc SCSI constants
  *************************************************************/
index ea509d1..995dae1 100644 (file)
 #define TRACE_OUT_OF_MEM     0x00000100
 #define TRACE_MINOR          0x00000200 /* less important events */
 #define TRACE_MGMT           0x00000400
-#define TRACE_MGMT_DEBUG     0x00000800
-#define TRACE_SCSI           0x00001000
-#define TRACE_SPECIAL        0x00002000 /* filtering debug, etc */
+#define TRACE_MGMT_MINOR     0x00000800
+#define TRACE_MGMT_DEBUG     0x00001000
+#define TRACE_SCSI           0x00002000
+#define TRACE_SPECIAL        0x00004000 /* filtering debug, etc */
 #define TRACE_ALL            0xffffffff
 /* Flags 0xXXXX0000 are local for users */
 
@@ -151,26 +152,12 @@ do {                                                                \
   }                                                                 \
 } while(0)
 
-#define TRACE_LOG_FLAG(log_flag, trace, format, args...)            \
-do {                                                                \
-  char *__tflag = log_flag;                                         \
-  if (trace_flag & (trace))                                         \
-  {                                                                 \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
-                            __LINE__) > 0)                          \
-    {                                                               \
-      __tflag = NO_FLAG;                                            \
-    }                                                               \
-  }                                                                 \
-  PRINT(NO_FLAG, "%s" format, __tflag, args);                       \
-} while(0)
-
 #define TRACE_BUFFER(message, buff, len)                            \
 do {                                                                \
   if (trace_flag & TRACE_BUFF)                                      \
   {                                                                 \
     char *__tflag = LOG_FLAG;                                       \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    if (debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                             __LINE__) > 0)                          \
     {                                                               \
       __tflag = NO_FLAG;                                            \
@@ -185,7 +172,7 @@ do {                                                                \
   if (trace_flag & (flag))                                          \
   {                                                                 \
     char *__tflag = LOG_FLAG;                                       \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    if (debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                             __LINE__) > 0)                          \
     {                                                               \
       __tflag = NO_FLAG;                                            \
@@ -195,11 +182,18 @@ do {                                                                \
   }                                                                 \
 } while(0)
 
+#define PRINT_BUFFER(message, buff, len)                            \
+do {                                                                \
+    PRINT(NO_FLAG, "%s:", message);                                 \
+    debug_print_buffer(buff, len);                                  \
+} while(0)
+
 #else  /* DEBUG || TRACING */
 
 #define TRACE(trace, args...) {}
 #define TRACE_BUFFER(message, buff, len) {}
 #define TRACE_BUFF_FLAG(flag, message, buff, len) {}
+#define PRINT_BUFFER(message, buff, len) {}
 
 #endif /* DEBUG || TRACING */
 
@@ -210,7 +204,7 @@ do {                                                                \
   if (trace_flag & TRACE_MEMORY)                                    \
   {                                                                 \
     char *__tflag = LOG_FLAG;                                       \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    if (debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                             __LINE__) > 0)                          \
     {                                                               \
       __tflag = NO_FLAG;                                            \
@@ -224,7 +218,7 @@ do {                                                                \
   if (trace_flag & TRACE_DEBUG)                                     \
   {                                                                 \
     char *__tflag = LOG_FLAG;                                       \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    if (debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                             __LINE__) > 0)                          \
     {                                                               \
       __tflag = NO_FLAG;                                            \
@@ -238,7 +232,7 @@ do {                                                                \
   if (trace_flag & (TRACE_DEBUG|TRACE_SPECIAL))                     \
   {                                                                 \
     char *__tflag = LOG_FLAG;                                       \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    if (debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                             __LINE__) > 0)                          \
     {                                                               \
       __tflag = NO_FLAG;                                            \
@@ -252,7 +246,7 @@ do {                                                                \
   if (trace_flag & TRACE_MGMT_DEBUG)                                \
   {                                                                 \
     char *__tflag = LOG_FLAG;                                       \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    if (debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                             __LINE__) > 0)                          \
     {                                                               \
       __tflag = NO_FLAG;                                            \
@@ -266,7 +260,7 @@ do {                                                                \
   if (trace_flag & (TRACE_MGMT_DEBUG|TRACE_SPECIAL))                \
   {                                                                 \
     char *__tflag = LOG_FLAG;                                       \
-    if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    if (debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                             __LINE__) > 0)                          \
     {                                                               \
       __tflag = NO_FLAG;                                            \
@@ -275,22 +269,33 @@ do {                                                                \
   }                                                                 \
 } while(0)
 
-#define PRINT_ERROR(format, args...)                                  \
-do {                                                                   \
-  if (ERROR_FLAG != LOG_FLAG)                                          \
-  {                                                                    \
-    TRACE_LOG_FLAG(LOG_FLAG, trace_flag, "***ERROR*** " format, args); \
-  }                                                                    \
-  TRACE_LOG_FLAG(ERROR_FLAG, trace_flag, "***ERROR*** " format, args); \
+#define PRINT_LOG_FLAG(log_flag, format, args...)                   \
+do {                                                                \
+  char *__tflag = log_flag;                                         \
+  if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,    \
+                          __LINE__) > 0)                            \
+  {                                                                 \
+    __tflag = NO_FLAG;                                              \
+  }                                                                 \
+  PRINT(NO_FLAG, "%s" format, __tflag, args);                       \
+} while(0)
+
+#define PRINT_ERROR(format, args...)                               \
+do {                                                                \
+  if (ERROR_FLAG != LOG_FLAG)                                       \
+  {                                                                 \
+    PRINT_LOG_FLAG(LOG_FLAG, "***ERROR*** " format, args);          \
+  }                                                                 \
+  PRINT_LOG_FLAG(ERROR_FLAG, "***ERROR*** " format, args);          \
 } while(0)
 
-#define PRINT_INFO(format, args...)                     \
-do {                                                    \
-  if (INFO_FLAG != LOG_FLAG)                            \
-  {                                                     \
-    TRACE_LOG_FLAG(LOG_FLAG, trace_flag, format, args); \
-  }                                                     \
-  TRACE_LOG_FLAG(INFO_FLAG, trace_flag, format, args);  \
+#define PRINT_INFO(format, args...)                   \
+do {                                                  \
+  if (INFO_FLAG != LOG_FLAG)                          \
+  {                                                   \
+    PRINT_LOG_FLAG(LOG_FLAG, format, args);           \
+  }                                                   \
+  PRINT_LOG_FLAG(INFO_FLAG, format, args);            \
 } while(0)
 
 #define TRACE_ENTRY()                                 \
index 1289886..53db9f9 100644 (file)
@@ -3,7 +3,9 @@
  *  
  *  Copyright (C) 2007 Vladislav Bolkhovitin <vst@vlnb.net>
  *  
- *  Contains macroses for execution tracing and error reporting
+ *  Contains constants and data structures for scst_user module.
+ *  See http://scst.sourceforge.net/doc/scst_user_spec.txt or
+ *  scst_user_spec.txt for description.
  * 
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -23,7 +25,7 @@
 
 #define DEV_USER_NAME                "scst_user"
 #define DEV_USER_PATH                  "/dev/"
-#define DEV_USER_VERSION               961
+#define DEV_USER_VERSION               962
 
 /* 
  * Chosen so sizeof(scst_user_sess) <= sizeof(scst_user_scsi_cmd_exec) 
@@ -91,6 +93,14 @@ struct scst_user_opt
        uint8_t prio_queue_type;
        uint8_t partial_transfers_type;
        int32_t partial_len;
+
+       /* SCSI control mode page parameters, see SPC */
+       uint8_t tst;
+       uint8_t queue_alg;
+       uint8_t tas;
+       uint8_t swp;
+
+       uint8_t has_own_order_mgmt;
 };
 
 struct scst_user_dev_desc
@@ -170,6 +180,7 @@ struct scst_user_scsi_on_free_cmd
        uint8_t buffer_cached;
        uint8_t aborted;
        uint8_t status;
+       uint8_t delivery_status;
 };
 
 struct scst_user_on_cached_mem_free
index 5e6c55c..a9f6569 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/cdrom.h>
+#include <scsi/scsi_host.h>
 
 #define LOG_PREFIX     "dev_cdrom"
 
@@ -210,7 +211,7 @@ int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
 
        scst_cdrom_generic_parse(cmd, info_cdb, cdrom_get_block_shift);
 
-       cmd->retries = 1;
+       cmd->retries = SCST_PASSTHROUGH_RETRIES;
 
        if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
                cmd->timeout = CDROM_SMALL_TIMEOUT;
index 2e6bd3c..09eef66 100644 (file)
@@ -17,6 +17,8 @@
  *  GNU General Public License for more details.
  */
 
+#include <scsi/scsi_host.h>
+
 #define LOG_PREFIX      "dev_changer"
 
 #include "scsi_tgt.h"
@@ -130,7 +132,7 @@ int changer_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
 
        scst_changer_generic_parse(cmd, info_cdb, 0);
 
-       cmd->retries = 1;
+       cmd->retries = SCST_PASSTHROUGH_RETRIES;
 
        if (info_cdb->flags & SCST_LONG_TIMEOUT) {
                cmd->timeout = CHANGER_LONG_TIMEOUT;
index 89a6e81..a70267d 100644 (file)
@@ -15,8 +15,8 @@
 
 #ifdef DEBUG
 #define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \
-        TRACE_LINE | TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | \
-        TRACE_MGMT_DEBUG | TRACE_SPECIAL)
+        TRACE_LINE | TRACE_FUNCTION | TRACE_MGMT | TRACE_MGMT_MINOR | \
+        TRACE_MINOR | TRACE_MGMT_DEBUG | TRACE_SPECIAL)
 #else
 #define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
        TRACE_MINOR | TRACE_SPECIAL)
@@ -29,6 +29,8 @@ static unsigned long dh_trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
 #define trace_log_tbl  NULL
 #endif
 
+#define SCST_PASSTHROUGH_RETRIES       0
+
 static struct scst_proc_data dev_handler_log_proc_data;
 
 static int dev_handler_log_info_show(struct seq_file *seq, void *v)
index 851448a..e0fdd99 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <scsi/scsi_host.h>
 
 #define LOG_PREFIX           "dev_disk"
 
@@ -282,7 +283,7 @@ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
 
        scst_sbc_generic_parse(cmd, info_cdb, disk_get_block_shift);
 
-       cmd->retries = 1;
+       cmd->retries = SCST_PASSTHROUGH_RETRIES;
 
        if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
                cmd->timeout = DISK_SMALL_TIMEOUT;
index 61f6733..9258468 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <scsi/scsi_host.h>
 
 #define LOG_PREFIX             "dev_modisk"
 
@@ -297,7 +298,7 @@ int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
 
        scst_modisk_generic_parse(cmd, info_cdb, modisk_get_block_shift);
 
-       cmd->retries = 1;
+       cmd->retries = SCST_PASSTHROUGH_RETRIES;
 
        if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
                cmd->timeout = MODISK_SMALL_TIMEOUT;
index 5de25ed..efa75a2 100644 (file)
@@ -17,6 +17,8 @@
  *  GNU General Public License for more details.
  */
 
+#include <scsi/scsi_host.h>
+
 #define LOG_PREFIX "dev_processor"
 
 #include "scsi_tgt.h"
@@ -130,7 +132,7 @@ int processor_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
 
        scst_processor_generic_parse(cmd, info_cdb, 0);
 
-       cmd->retries = 1;
+       cmd->retries = SCST_PASSTHROUGH_RETRIES;
 
        if (info_cdb->flags & SCST_LONG_TIMEOUT) {
                cmd->timeout = PROCESSOR_LONG_TIMEOUT;
index a6209e9..2527f2c 100644 (file)
@@ -19,6 +19,8 @@
 
 #define LOG_PREFIX      "dev_raid"
 
+#include <scsi/scsi_host.h>
+
 #include "scsi_tgt.h"
 #include "scst_dev_handler.h"
 
@@ -30,9 +32,9 @@
   parse_atomic:     1,         \
 /*  dev_done_atomic:  1,*/      \
   attach:   raid_attach,       \
-/*  detach:   raid_detach,*/ \
+/*  detach:   raid_detach,*/   \
   parse:    raid_parse,        \
-/*  dev_done: raid_done*/    \
+/*  dev_done: raid_done*/      \
 }
 
 #define RAID_RETRIES       2
@@ -130,7 +132,7 @@ int raid_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
 
        scst_raid_generic_parse(cmd, info_cdb, 0);
 
-       cmd->retries = 1;
+       cmd->retries = SCST_PASSTHROUGH_RETRIES;
 
        if (info_cdb->flags & SCST_LONG_TIMEOUT) {
                cmd->timeout = RAID_LONG_TIMEOUT;
index 0de4e33..cc50926 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <scsi/scsi_host.h>
 
 #define LOG_PREFIX           "dev_tape"
 
@@ -285,7 +286,7 @@ int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
 
        scst_tape_generic_parse(cmd, info_cdb, tape_get_block_size);
 
-       cmd->retries = 1;
+       cmd->retries = SCST_PASSTHROUGH_RETRIES;
 
        if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
                cmd->timeout = TAPE_SMALL_TIMEOUT;
index 961a50a..3d395ac 100644 (file)
@@ -59,6 +59,12 @@ struct scst_user_dev
        unsigned short internal_reset_active:1;
        unsigned short pre_unreg_sess_active:1; /* just a small optimization */
 
+       unsigned short tst:3;
+       unsigned short queue_alg:4;
+       unsigned short tas:1;
+       unsigned short swp:1;
+       unsigned short has_own_order_mgmt:1;
+
        unsigned short detach_cmd_count;
 
        int (*generic_parse)(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb,
@@ -82,6 +88,8 @@ struct scst_user_dev
        unsigned int handle_counter;
        struct list_head ucmd_hash[1<<DEV_USER_CMD_HASH_ORDER];
 
+       struct scst_device *sdev;
+
        int virt_id;
        struct list_head dev_list_entry;
        char name[SCST_MAX_NAME];
@@ -552,6 +560,14 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd)
 
        TRACE_ENTRY();
 
+       if (unlikely(ucmd->cmd->data_buf_tgt_alloc)) {
+               PRINT_ERROR("Target driver %s requested own memory "
+                       "allocation", ucmd->cmd->tgtt->name);
+               scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
+               res = SCST_CMD_STATE_PRE_XMIT_RESP;
+               goto out;
+       }
+
        ucmd->state = UCMD_STATE_BUF_ALLOCING;
        cmd->data_buf_alloced = 1;
 
@@ -560,7 +576,7 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd)
                goto out;
        else if (rc < 0) {
                scst_set_busy(cmd);
-               res = SCST_CMD_STATE_XMIT_RESP;
+               res = SCST_CMD_STATE_PRE_XMIT_RESP;
                goto out;
        }
 
@@ -671,16 +687,14 @@ static int dev_user_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
                rc = dev->generic_parse(cmd, info_cdb, dev_user_get_block);
                if ((rc != 0) || (info_cdb->flags & SCST_INFO_INVALID))
                        goto out_invalid;
-               ucmd->cmd->skip_parse = 1;
                break;
 
        case SCST_USER_PARSE_EXCEPTION:
                TRACE_DBG("PARSE EXCEPTION: ucmd %p", ucmd);
                rc = dev->generic_parse(cmd, info_cdb, dev_user_get_block);
-               if ((rc == 0) && (!(info_cdb->flags & SCST_INFO_INVALID))) {
-                       ucmd->cmd->skip_parse = 1;
+               if ((rc == 0) && (!(info_cdb->flags & SCST_INFO_INVALID)))
                        break;
-               else if (rc == SCST_CMD_STATE_NEED_THREAD_CTX) {
+               else if (rc == SCST_CMD_STATE_NEED_THREAD_CTX) {
                        TRACE_MEM("Restarting PARSE to thread context "
                                "(ucmd %p)", ucmd);
                        res = SCST_CMD_STATE_NEED_THREAD_CTX;
@@ -691,7 +705,6 @@ static int dev_user_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
        case SCST_USER_PARSE_CALL:
                TRACE_DBG("Preparing PARSE for user space (ucmd=%p, h=%d, "
                        "bufflen %d)", ucmd, ucmd->h, cmd->bufflen);
-               ucmd->cmd->skip_parse = 1;
                ucmd->user_cmd.cmd_h = ucmd->h;
                ucmd->user_cmd.subcode = SCST_USER_PARSE;
                ucmd->user_cmd.parse_cmd.sess_h = (unsigned long)cmd->tgt_dev;
@@ -733,7 +746,7 @@ out_invalid:
        scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
 
 out_error:
-       res = SCST_CMD_STATE_XMIT_RESP;
+       res = SCST_CMD_STATE_PRE_XMIT_RESP;
        goto out;
 }
 
@@ -850,6 +863,7 @@ static void dev_user_on_free_cmd(struct scst_cmd *cmd)
        ucmd->user_cmd.on_free_cmd.buffer_cached = ucmd->buff_cached;
        ucmd->user_cmd.on_free_cmd.aborted = ucmd->aborted;
        ucmd->user_cmd.on_free_cmd.status = cmd->status;
+       ucmd->user_cmd.on_free_cmd.delivery_status = cmd->delivery_status;
 
        ucmd->state = UCMD_STATE_ON_FREEING;
 
@@ -1043,7 +1057,7 @@ out_nomem:
        /* go through */
 
 out_err:
-       ucmd->cmd->state = SCST_CMD_STATE_XMIT_RESP;
+       ucmd->cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
        goto out;
 
 out_unmap:
@@ -1084,7 +1098,7 @@ static int dev_user_process_reply_alloc(struct scst_user_cmd *ucmd,
                res = dev_user_map_buf(ucmd, reply->alloc_reply.pbuf, pages);
        } else {
                scst_set_busy(ucmd->cmd);
-               ucmd->cmd->state = SCST_CMD_STATE_XMIT_RESP;
+               ucmd->cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
        }
 
 out_process:
@@ -1868,7 +1882,6 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
                if (test_bit(SCST_CMD_ABORTED,  &ucmd->cmd->cmd_flags))
                        ucmd->aborted = 1;
                else {
-                       ucmd->cmd->completed = 1;
                        if (busy)
                                scst_set_busy(ucmd->cmd);
                        else
@@ -2202,8 +2215,14 @@ static int dev_user_attach(struct scst_device *sdev)
        }
 
        sdev->p_cmd_lists = &dev->cmd_lists;
-
        sdev->dh_priv = dev;
+       sdev->tst = dev->tst;
+       sdev->queue_alg = dev->queue_alg;
+       sdev->swp = dev->swp;
+       sdev->tas = dev->tas;
+       sdev->has_own_order_mgmt = dev->has_own_order_mgmt;
+
+       dev->sdev = sdev;
 
        PRINT_INFO("Attached user space SCSI target virtual device \"%s\"",
                dev->name);
@@ -2226,6 +2245,7 @@ static void dev_user_detach(struct scst_device *sdev)
 
        /* dev will be freed by the caller */
        sdev->dh_priv = NULL;
+       dev->sdev = NULL;
        
        TRACE_EXIT();
        return;
@@ -2610,7 +2630,6 @@ static int dev_user_register_dev(struct file *file,
        dev->devtype.exec_atomic = 0; /* no point to make it 1 */
        dev->devtype.dev_done_atomic = 1;
        dev->devtype.no_proc = 1;
-       dev->devtype.inc_expected_sn_on_done = 1;
        dev->devtype.attach = dev_user_attach;
        dev->devtype.detach = dev_user_detach;
        dev->devtype.attach_tgt = dev_user_attach_tgt;
@@ -2714,6 +2733,18 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
                goto out;
        }
 
+       if (((opt->tst != SCST_CONTR_MODE_ONE_TASK_SET) &&
+            (opt->tst != SCST_CONTR_MODE_SEP_TASK_SETS)) ||
+           ((opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) &&
+            (opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER)) ||
+           (opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1)) {
+               PRINT_ERROR("Invalid SCSI option (tst %x, queue_alg %x, swp %x, "
+                       "tas %x, has_own_order_mgmt %x)", opt->tst,
+                       opt->queue_alg, opt->swp, opt->tas, opt->has_own_order_mgmt);
+               res = -EINVAL;
+               goto out;
+       }
+
        if ((dev->prio_queue_type != opt->prio_queue_type) &&
            (opt->prio_queue_type == SCST_USER_PRIO_QUEUE_SINGLE)) {
                struct scst_user_cmd *u, *t;
@@ -2732,6 +2763,19 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
        dev->partial_transfers_type = opt->partial_transfers_type;
        dev->partial_len = opt->partial_len;
 
+       dev->tst = opt->tst;
+       dev->queue_alg = opt->queue_alg;
+       dev->swp = opt->swp;
+       dev->tas = opt->tas;
+       dev->has_own_order_mgmt = opt->has_own_order_mgmt;
+       if (dev->sdev != NULL) {
+               dev->sdev->tst = opt->tst;
+               dev->sdev->queue_alg = opt->queue_alg;
+               dev->sdev->swp = opt->swp;
+               dev->sdev->tas = opt->tas;
+               dev->sdev->has_own_order_mgmt = opt->has_own_order_mgmt;
+       }
+
        dev_user_setup_functions(dev);
 
 out:
@@ -2791,6 +2835,11 @@ static int dev_user_get_opt(struct file *file, void *arg)
        opt.prio_queue_type = dev->prio_queue_type;
        opt.partial_transfers_type = dev->partial_transfers_type;
        opt.partial_len = dev->partial_len;
+       opt.tst = dev->tst;
+       opt.queue_alg = dev->queue_alg;
+       opt.tas = dev->tas;
+       opt.swp = dev->swp;
+       opt.has_own_order_mgmt = dev->has_own_order_mgmt;
 
        TRACE_DBG("parse_type %x, on_free_cmd_type %x, memory_reuse_type %x, "
                "partial_transfers_type %x, partial_len %d", opt.parse_type,
index 9a9c1d3..071db9a 100644 (file)
@@ -88,6 +88,16 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
 #define VDISK_NAME                     "vdisk"
 #define VCDROM_NAME                    "vcdrom"
 
+#define DEF_TST                                SCST_CONTR_MODE_SEP_TASK_SETS
+/*
+ * Since we can't control backstorage device's reordering, we have to always
+ * report unrestricted reordering.
+ */
+#define DEF_QUEUE_ALG_WT               SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER
+#define DEF_QUEUE_ALG                  SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER
+#define DEF_SWP                                0
+#define DEF_TAS                                0
+
 #define VDISK_PROC_HELP                        "help"
 
 static unsigned int random_values[256] = {
@@ -188,7 +198,8 @@ struct scst_vdisk_dev {
 struct scst_vdisk_tgt_dev {
        /*
         * Used without locking since SCST core ensures that only commands
-        * of the same type per tgt_dev can be processed simultaneously
+        * with the same ORDERED type per tgt_dev can be processed
+        * simultaneously.
         */
        enum scst_cmd_queue_type last_write_cmd_queue_type;
 };
@@ -223,6 +234,7 @@ static void vdisk_exec_verify(struct scst_cmd *cmd,
 static void vdisk_exec_read_capacity(struct scst_cmd *cmd);
 static void vdisk_exec_read_capacity16(struct scst_cmd *cmd);
 static void vdisk_exec_inquiry(struct scst_cmd *cmd);
+static void vdisk_exec_request_sense(struct scst_cmd *cmd);
 static void vdisk_exec_mode_sense(struct scst_cmd *cmd);
 static void vdisk_exec_mode_select(struct scst_cmd *cmd);
 static void vdisk_exec_log(struct scst_cmd *cmd);
@@ -236,6 +248,8 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
 static int vcdrom_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type);
 static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
        int length, int *eof, struct scst_dev_type *dev_type);
+static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
+       struct scst_tgt_dev *tgt_dev);
 
 #define VDISK_TYPE {                   \
   name:         VDISK_NAME,            \
@@ -252,6 +266,7 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
   exec:         vdisk_do_job,          \
   read_proc:    vdisk_read_proc,       \
   write_proc:   vdisk_write_proc,      \
+  task_mgmt_fn: vdisk_task_mgmt_fn,    \
 }
 
 #define VDISK_BLK_TYPE {               \
@@ -262,13 +277,13 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
   exec_atomic:  0,                     \
   dev_done_atomic: 1,                  \
   no_proc: 1,                          \
-  inc_expected_sn_on_done: 1,          \
   attach:       vdisk_attach,          \
   detach:       vdisk_detach,          \
   attach_tgt:   vdisk_attach_tgt,      \
   detach_tgt:   vdisk_detach_tgt,      \
   parse:        vdisk_parse,           \
   exec:         vdisk_do_job,          \
+  task_mgmt_fn: vdisk_task_mgmt_fn,    \
 }
 
 #define VCDROM_TYPE {                  \
@@ -286,6 +301,7 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
   exec:         vcdrom_exec,           \
   read_proc:    vcdrom_read_proc,      \
   write_proc:   vcdrom_write_proc,     \
+  task_mgmt_fn: vdisk_task_mgmt_fn,    \
 }
 
 static DEFINE_MUTEX(scst_vdisk_mutex);
@@ -469,6 +485,14 @@ static int vdisk_attach(struct scst_device *dev)
 
        dev->dh_priv = virt_dev;
 
+       dev->tst = DEF_TST;
+       if (virt_dev->wt_flag)
+               dev->queue_alg = DEF_QUEUE_ALG_WT;
+       else
+               dev->queue_alg = DEF_QUEUE_ALG;
+       dev->swp = DEF_SWP;
+       dev->tas = DEF_TAS;
+
 out:
        TRACE_EXIT();
        return res;
@@ -823,7 +847,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
                        /* ToDo: BLOCKIO VERIFY */
                        vdisk_exec_write(cmd, thr, loff);
                        /* O_SYNC flag is used for WT devices */
-                       if (cmd->status == 0)
+                       if (scsi_status_is_good(cmd->status))
                                vdisk_exec_verify(cmd, thr, loff);
                        else if (do_fsync)
                                vdisk_fsync(thr, loff, data_len, cmd);
@@ -890,6 +914,9 @@ static int vdisk_do_job(struct scst_cmd *cmd)
        case INQUIRY:
                vdisk_exec_inquiry(cmd);
                break;
+       case REQUEST_SENSE:
+               vdisk_exec_request_sense(cmd);
+               break;
        case READ_CAPACITY:
                vdisk_exec_read_capacity(cmd);
                break;
@@ -989,7 +1016,7 @@ static int vcdrom_exec(struct scst_cmd *cmd)
                TRACE_DBG("%s", "CDROM empty");
                scst_set_cmd_error(cmd,
                        SCST_LOAD_SENSE(scst_sense_not_ready));
-               goto out_complete;
+               goto out_done;
        }
 
        if (virt_dev->media_changed && (cmd->cdb[0] != INQUIRY) && 
@@ -1001,7 +1028,7 @@ static int vcdrom_exec(struct scst_cmd *cmd)
                        scst_set_cmd_error(cmd,
                                SCST_LOAD_SENSE(scst_sense_medium_changed_UA));
                        spin_unlock(&virt_dev->flags_lock);
-                       goto out_complete;
+                       goto out_done;
                }
                spin_unlock(&virt_dev->flags_lock);
        }
@@ -1012,8 +1039,7 @@ out:
        TRACE_EXIT();
        return SCST_EXEC_COMPLETED;
 
-out_complete:
-       cmd->completed = 1;
+out_done:
        cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
        goto out;
 }
@@ -1193,6 +1219,36 @@ out:
        return;
 }
 
+static void vdisk_exec_request_sense(struct scst_cmd *cmd)
+{
+       int32_t length;
+       uint8_t *address;
+
+       TRACE_ENTRY();
+
+       length = scst_get_buf_first(cmd, &address);
+       TRACE_DBG("length %d", length);
+       if (unlikely(length < SCST_STANDARD_SENSE_LEN)) {
+               PRINT_ERROR("scst_get_buf_first() failed or too small "
+                       "requested buffer (returned %d)", length);
+               scst_set_cmd_error(cmd,
+                   SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
+               if (length > 0)
+                       goto out_put;
+               else
+                       goto out;
+       }
+
+       scst_set_sense(address, length, SCST_LOAD_SENSE(scst_sense_no_sense));
+
+out_put:
+       scst_put_buf(cmd, address);
+
+out:
+       TRACE_EXIT();
+       return;
+}
+
 /* 
  * <<Following mode pages info copied from ST318451LW with some corrections>>
  *
@@ -1256,14 +1312,38 @@ static int vdisk_caching_pg(unsigned char *p, int pcontrol,
 static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol,
                            struct scst_vdisk_dev *virt_dev)
 {      /* Control mode page for mode_sense */
-       const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0x20, 0, 0, 0x40, 0, 0,
+       const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0, 0, 0, 0, 0, 0,
                                           0, 0, 0x2, 0x4b};
 
        memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
-       if (!virt_dev->wt_flag && !virt_dev->nv_cache)
-               p[3] |= 0x10; /* Enable unrestricted reordering */
-       if (1 == pcontrol)
+       switch(pcontrol) {
+       case 0:
+               p[2] |= virt_dev->dev->tst << 5;
+               p[3] |= virt_dev->dev->queue_alg << 4;
+               p[4] |= virt_dev->dev->swp << 3;
+               p[5] |= virt_dev->dev->tas << 6;
+               break;
+       case 1:
                memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
+#if 0 /* Too early, see corresponding comment in vdisk_exec_mode_select() */
+               p[2] |= 7 << 5;
+               p[3] |= 0xF << 4;
+               p[4] |= 1 << 3;
+               p[5] |= 1 << 6;
+#endif
+               break;
+       case 2:
+               p[2] |= DEF_TST << 5;
+               if (virt_dev->wt_flag)
+                       p[3] |= DEF_QUEUE_ALG_WT << 4;
+               else
+                       p[3] |= DEF_QUEUE_ALG << 4;
+               p[4] |= DEF_SWP << 3;
+               p[5] |= DEF_TAS << 6;
+               break;
+       default:
+               sBUG();
+       }
        return sizeof(ctrl_m_pg);
 }
 
@@ -1519,6 +1599,25 @@ static void vdisk_exec_mode_select(struct scst_cmd *cmd)
                                goto out_put;
                        }
                        break;
+#if 0 /* 
+       * It's too early to implement it, since we can't control the backstorage
+       * device parameters. ToDo
+       */
+               } else if ((address[offset] & 0x3f) == 0xA) {   /* Control page */
+                       if (address[offset + 1] != 0xA) {
+                               PRINT_ERROR("%s", "MODE SELECT: Invalid "
+                                       "control page request");
+                               scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
+                                       scst_sense_invalid_field_in_parm_list));
+                               goto out_put;
+                       }
+#endif
+               } else {
+                       PRINT_ERROR("MODE SELECT: Invalid request %x", 
+                               address[offset] & 0x3f);
+                       scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
+                               scst_sense_invalid_field_in_parm_list));
+                       goto out_put;
                }
                offset += address[offset + 1];
        }
@@ -2366,6 +2465,29 @@ out:
        return dev;
 }
 
+static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
+       struct scst_tgt_dev *tgt_dev)
+{
+       TRACE_ENTRY();
+
+       if ((mcmd->fn == SCST_LUN_RESET) || (mcmd->fn == SCST_TARGET_RESET)) {
+               /* Restore default values */
+               struct scst_device *dev = tgt_dev->dev;
+               struct scst_vdisk_dev *virt_dev =
+                       (struct scst_vdisk_dev *)dev->dh_priv;
+               dev->tst = DEF_TST;
+               if (virt_dev->wt_flag)
+                       dev->queue_alg = DEF_QUEUE_ALG_WT;
+               else
+                       dev->queue_alg = DEF_QUEUE_ALG;
+               dev->swp = DEF_SWP;
+               dev->tas = DEF_TAS;
+       }
+
+       TRACE_EXIT();
+       return SCST_DEV_TM_NOT_COMPLETED;
+}
+
 /* 
  * Called when a file in the /proc/VDISK_NAME/VDISK_NAME is read
  */
index f509233..319ea91 100644 (file)
@@ -38,6 +38,8 @@
 #include "scst_cdbprobe.h"
 
 static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev);
+int scst_check_internal_sense(struct scst_device *dev, int result,
+       uint8_t *sense, int sense_len);
 
 void scst_set_cmd_error_status(struct scst_cmd *cmd, int status)
 {
@@ -50,6 +52,8 @@ void scst_set_cmd_error_status(struct scst_cmd *cmd, int status)
        cmd->tgt_resp_flags = SCST_TSC_FLAG_STATUS;
        cmd->resp_data_len = 0;
 
+       cmd->completed = 1;
+
        TRACE_EXIT();
        return;
 }
@@ -67,6 +71,19 @@ void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq)
        return;
 }
 
+void scst_set_sense(uint8_t *buffer, int len, int key,
+       int asc, int ascq)
+{
+       memset(buffer, 0, len);
+       buffer[0] = 0x70;       /* Error Code                   */
+       buffer[2] = key;        /* Sense Key                    */
+       buffer[7] = 0x0a;       /* Additional Sense Length      */
+       buffer[12] = asc;       /* ASC                          */
+       buffer[13] = ascq;      /* ASCQ                         */
+       TRACE_BUFFER("Sense set", buffer, len);
+       return;
+}
+
 void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense, 
        unsigned int len)
 {
@@ -91,15 +108,15 @@ void scst_set_busy(struct scst_cmd *cmd)
 
        if ((c <= 1) || (cmd->sess->init_phase != SCST_SESS_IPH_READY)) {
                scst_set_cmd_error_status(cmd, SAM_STAT_BUSY);
-               TRACE_MGMT_DBG("Sending BUSY status to initiator %s "
+               TRACE(TRACE_MGMT_MINOR, "Sending BUSY status to initiator %s "
                        "(cmds count %d, queue_type %x, sess->init_phase %d)",
                        cmd->sess->initiator_name, c,
                        cmd->queue_type, cmd->sess->init_phase);
        } else {
                scst_set_cmd_error_status(cmd, SAM_STAT_TASK_SET_FULL);
-               TRACE_MGMT_DBG("Sending QUEUE_FULL status to initiator %s "
-                       "(cmds count %d, queue_type %x, sess->init_phase %d)",
-                       cmd->sess->initiator_name, c,
+               TRACE(TRACE_MGMT_MINOR, "Sending QUEUE_FULL status to "
+                       "initiator %s (cmds count %d, queue_type %x, "
+                       "sess->init_phase %d)", cmd->sess->initiator_name, c,
                        cmd->queue_type, cmd->sess->init_phase);
        }
 
@@ -297,9 +314,8 @@ int scst_destroy_acg(struct scst_acg *acg)
        {
                struct scst_tgt_dev *tgt_dev, *tt;
                list_for_each_entry_safe(tgt_dev, tt,
-                        &acg_dev->dev->dev_tgt_dev_list,
-                        dev_tgt_dev_list_entry)
-               {
+                                &acg_dev->dev->dev_tgt_dev_list,
+                                dev_tgt_dev_list_entry) {
                        if (tgt_dev->acg_dev == acg_dev)
                                scst_free_tgt_dev(tgt_dev);
                }
@@ -436,7 +452,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
        spin_lock_bh(&scst_temp_UA_lock);
        scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
                SCST_LOAD_SENSE(scst_sense_reset_UA));
-       scst_alloc_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA));
+       scst_alloc_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA), 0);
        spin_unlock_bh(&scst_temp_UA_lock);
 
        tm_dbg_init_tgt_dev(tgt_dev, acg_dev);
@@ -489,42 +505,31 @@ out_free:
        goto out;
 }
 
-static void scst_send_release(struct scst_tgt_dev *tgt_dev);
+static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev);
 
 /* 
  * No locks supposed to be held, scst_mutex - held.
  * The activity is suspended.
  */
-void scst_reset_tgt_dev(struct scst_tgt_dev *tgt_dev, int nexus_loss)
+void scst_nexus_loss(struct scst_tgt_dev *tgt_dev)
 {
-       struct scst_device *dev = tgt_dev->dev;
+       TRACE_ENTRY();
 
-       if (dev->dev_reserved &&
-           !test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags)) 
-       {
-               /* This is one who holds the reservation */
-               struct scst_tgt_dev *tgt_dev_tmp;
-               list_for_each_entry(tgt_dev_tmp, &dev->dev_tgt_dev_list,
-                                   dev_tgt_dev_list_entry) 
-               {
-                       clear_bit(SCST_TGT_DEV_RESERVED,
-                                   &tgt_dev_tmp->tgt_dev_flags);
-               }
-               dev->dev_reserved = 0;
+       scst_clear_reservation(tgt_dev);
 
-               scst_send_release(tgt_dev);
-       }
+       /* With activity suspended the lock isn't needed, but let's be safe */
+       spin_lock_bh(&tgt_dev->tgt_dev_lock);
+       scst_free_all_UA(tgt_dev);
+       spin_unlock_bh(&tgt_dev->tgt_dev_lock);
 
        spin_lock_bh(&scst_temp_UA_lock);
-       if (nexus_loss) {
-               scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
-                       SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
-       } else {
-               scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
-                       SCST_LOAD_SENSE(scst_sense_reset_UA));
-       }
-       scst_check_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA));
+       scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
+               SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
+       scst_check_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA), 0);
        spin_unlock_bh(&scst_temp_UA_lock);
+
+       TRACE_EXIT();
+       return;
 }
 
 /* 
@@ -543,7 +548,7 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
        list_del(&tgt_dev->dev_tgt_dev_list_entry);
        list_del(&tgt_dev->sess_tgt_dev_list_entry);
 
-       scst_reset_tgt_dev(tgt_dev, 0);
+       scst_clear_reservation(tgt_dev);
        scst_free_all_UA(tgt_dev);
 
        if (dev->handler && dev->handler->detach_tgt) {
@@ -713,8 +718,7 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
        }
 
        list_for_each_entry_safe(tgt_dev, tt, &dev->dev_tgt_dev_list,
-                dev_tgt_dev_list_entry) 
-       {
+                        dev_tgt_dev_list_entry) {
                if (tgt_dev->acg_dev == acg_dev)
                        scst_free_tgt_dev(tgt_dev);
        }
@@ -882,7 +886,7 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
        rs_cmd->cdb_len = sizeof(request_sense);
        rs_cmd->data_direction = SCST_DATA_READ;
 
-       TRACE(TRACE_RETRY, "Adding REQUEST SENSE cmd %p to head of active "
+       TRACE(TRACE_MGMT_MINOR, "Adding REQUEST SENSE cmd %p to head of active "
                "cmd list ", rs_cmd);
        spin_lock_irq(&rs_cmd->cmd_lists->cmd_list_lock);
        list_add(&rs_cmd->cmd_list_entry, &rs_cmd->cmd_lists->active_cmd_list);
@@ -919,8 +923,8 @@ struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd)
 
        len = scst_get_buf_first(cmd, &buf);
 
-       if ((cmd->status == 0) && (len > 0) && SCST_SENSE_VALID(buf) &&
-           (!SCST_NO_SENSE(buf))) 
+       if (scsi_status_is_good(cmd->status) && (len > 0) &&
+           SCST_SENSE_VALID(buf) && (!SCST_NO_SENSE(buf))) 
        {
                TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned", 
                        buf, len);
@@ -930,7 +934,8 @@ struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd)
        } else {
                PRINT_ERROR("%s", "Unable to get the sense via "
                        "REQUEST SENSE, returning HARDWARE ERROR");
-               scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
+               scst_set_cmd_error(orig_cmd,
+                       SCST_LOAD_SENSE(scst_sense_hardw_error));
        }
 
        if (len > 0)
@@ -1011,7 +1016,7 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev)
        struct scsi_device *scsi_dev;
        unsigned char cdb[6];
        unsigned char *sense;
-       int rc;
+       int rc, i;
 
        TRACE_ENTRY();
        
@@ -1019,25 +1024,36 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev)
                goto out;
 
        /* We can't afford missing RELEASE due to memory shortage */
-       sense = kzalloc(SCST_SENSE_BUFFERSIZE, GFP_KERNEL|__GFP_NOFAIL);
+       sense = kmalloc(SCST_SENSE_BUFFERSIZE, GFP_KERNEL|__GFP_NOFAIL);
 
        scsi_dev = tgt_dev->dev->scsi_dev;
 
-       memset(cdb, 0, sizeof(cdb));
-       cdb[0] = RELEASE;
-       cdb[1] = (scsi_dev->scsi_level <= SCSI_2) ?
-           ((scsi_dev->lun << 5) & 0xe0) : 0;
+       for(i = 0; i < 5; i++) {
+               memset(cdb, 0, sizeof(cdb));
+               cdb[0] = RELEASE;
+               cdb[1] = (scsi_dev->scsi_level <= SCSI_2) ?
+                   ((scsi_dev->lun << 5) & 0xe0) : 0;
 
-       TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to SCSI "
-               "mid-level");
-       rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0,
-                       sense, SCST_DEFAULT_TIMEOUT, 3, GFP_KERNEL);
-       if (rc) {
-               PRINT_INFO("scsi_execute() failed: %d", rc);
-               goto out_free;
+               memset(sense, 0, SCST_SENSE_BUFFERSIZE);
+
+               TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to "
+                       "SCSI mid-level");
+               rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0,
+                               sense, SCST_DEFAULT_TIMEOUT, 0, GFP_KERNEL);
+               TRACE_DBG("MODE_SENSE done: %x", rc);
+
+               if (scsi_status_is_good(rc)) {
+                       break;
+               } else {
+                       PRINT_ERROR("RELEASE failed: %d", rc);
+                       TRACE_BUFFER("RELEASE sense", sense,
+                               SCST_SENSE_BUFFERSIZE);
+                       if (scst_check_internal_sense(tgt_dev->dev, rc,
+                                       sense, SCST_SENSE_BUFFERSIZE) != 0)
+                               break;
+               }
        }
 
-out_free:
        kfree(sense);
 
 out:
@@ -1046,6 +1062,31 @@ out:
 }
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
 
+static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev)
+{
+       struct scst_device *dev = tgt_dev->dev;
+
+       TRACE_ENTRY();
+
+       if (dev->dev_reserved &&
+           !test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags)) 
+       {
+               /* This is one who holds the reservation */
+               struct scst_tgt_dev *tgt_dev_tmp;
+               list_for_each_entry(tgt_dev_tmp, &dev->dev_tgt_dev_list,
+                                   dev_tgt_dev_list_entry) {
+                       clear_bit(SCST_TGT_DEV_RESERVED,
+                                   &tgt_dev_tmp->tgt_dev_flags);
+               }
+               dev->dev_reserved = 0;
+
+               scst_send_release(tgt_dev);
+       }
+
+       TRACE_EXIT();
+       return;
+}
+
 struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
        const char *initiator_name)
 {
@@ -1190,11 +1231,12 @@ struct scst_cmd *scst_alloc_cmd(int gfp_mask)
        memset(cmd, 0, sizeof(*cmd));
 #endif
 
+       cmd->state = SCST_CMD_STATE_INIT_WAIT;
        atomic_set(&cmd->cmd_ref, 1);
        cmd->cmd_lists = &scst_main_cmd_lists;
        cmd->queue_type = SCST_CMD_QUEUE_SIMPLE;
        cmd->timeout = SCST_DEFAULT_TIMEOUT;
-       cmd->retries = 1;
+       cmd->retries = 0;
        cmd->data_len = -1;
        cmd->tgt_resp_flags = SCST_TSC_FLAG_STATUS;
        cmd->resp_data_len = -1;
@@ -2191,6 +2233,101 @@ out:
        return res;
 }
 
+int scst_check_internal_sense(struct scst_device *dev, int result,
+       uint8_t *sense, int sense_len)
+{
+       TRACE_ENTRY();
+
+       if (host_byte(result) == DID_RESET) {
+               scst_set_sense(sense, sense_len,
+                       SCST_LOAD_SENSE(scst_sense_reset_UA));
+               scst_dev_check_set_UA(dev, NULL, sense, sense_len);
+       } else if (SCST_SENSE_VALID(sense) && scst_is_ua_sense(sense))
+               scst_dev_check_set_UA(dev, NULL, sense, sense_len);
+
+       TRACE_EXIT();
+       return 0;
+}
+
+int scst_obtain_device_parameters(struct scst_device *dev)
+{
+       int res = 0, i;
+       uint8_t cmd[16];
+       uint8_t buffer[4+0x0A];
+       uint8_t sense_buffer[SCST_SENSE_BUFFERSIZE];
+
+       TRACE_ENTRY();
+
+       sBUG_ON(in_interrupt() || in_atomic());
+       EXTRACHECKS_BUG_ON(dev->scsi_dev == NULL);
+
+       for(i = 0; i < 5; i++) {
+               /* Get control mode page */
+               memset(cmd, 0, sizeof(cmd));
+               cmd[0] = MODE_SENSE;
+               cmd[1] = 8; /* DBD */
+               cmd[2] = 0x0A;
+               cmd[4] = sizeof(buffer);
+
+               memset(buffer, 0, sizeof(buffer));
+               memset(sense_buffer, 0, sizeof(sense_buffer));
+
+               TRACE_DBG("%s", "Doing MODE_SENSE");
+               res = scsi_execute(dev->scsi_dev, cmd, SCST_DATA_READ, buffer, 
+                          sizeof(buffer), sense_buffer, SCST_DEFAULT_TIMEOUT,
+                           0, GFP_KERNEL);
+
+               TRACE_DBG("MODE_SENSE done: %x", res);
+
+               if (scsi_status_is_good(res)) {
+                       int q;
+
+                       TRACE_BUFFER("Returned control mode page data", buffer,
+                               sizeof(buffer));
+
+                       dev->tst = buffer[4+2] >> 5;
+                       q = buffer[4+3] >> 4;
+                       if (q > SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER) {
+                               PRINT_ERROR("Too big QUEUE ALG %x, dev "
+                                       "%d:%d:%d:%d", dev->queue_alg,
+                                       dev->scsi_dev->host->host_no, dev->scsi_dev->channel,
+                                       dev->scsi_dev->id, dev->scsi_dev->lun);
+                       }
+                       dev->queue_alg = q;
+                       dev->swp = (buffer[4+4] & 0x8) >> 3;
+                       dev->tas = (buffer[4+5] & 0x40) >> 6;
+
+                       /*
+                        * Unfortunately, SCSI ML doesn't provide a way to
+                        * specify commands task attribute, so we can rely on
+                        * device's restricted reordering only.
+                        */
+                       dev->has_own_order_mgmt = !dev->queue_alg;
+
+                       TRACE(TRACE_MGMT_MINOR, "Device %d:%d:%d:%d: TST %x, "
+                               "QUEUE ALG %x, SWP %x, TAS %x, has_own_order_mgmt "
+                               "%d", dev->scsi_dev->host->host_no,
+                               dev->scsi_dev->channel, dev->scsi_dev->id,
+                               dev->scsi_dev->lun, dev->tst, dev->queue_alg,
+                               dev->swp, dev->tas, dev->has_own_order_mgmt);
+
+                       goto out;
+               } else {
+                       PRINT_ERROR("Internal MODE_SENSE failed: %d", res);
+                       TRACE_BUFFER("MODE_SENSE sense", sense_buffer,
+                               sizeof(sense_buffer));
+                       if (scst_check_internal_sense(dev, res, sense_buffer,
+                                       sizeof(sense_buffer)) != 0)
+                               break;
+               }
+       }
+       res = -ENODEV;
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
 /* Called under dev_lock and BH off */
 void scst_process_reset(struct scst_device *dev,
        struct scst_session *originator, struct scst_cmd *exclude_cmd,
@@ -2205,8 +2342,7 @@ void scst_process_reset(struct scst_device *dev,
        if (dev->dev_reserved) {
                /* Either scst_mutex held or exclude_cmd non-NULL */
                list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
-                                   dev_tgt_dev_list_entry) 
-               {
+                                   dev_tgt_dev_list_entry) {
                        TRACE(TRACE_MGMT, "Clearing RESERVE'ation for tgt_dev "
                                "lun %Ld", tgt_dev->lun);
                        clear_bit(SCST_TGT_DEV_RESERVED,
@@ -2215,26 +2351,22 @@ void scst_process_reset(struct scst_device *dev,
                dev->dev_reserved = 0;
                /*
                 * There is no need to send RELEASE, since the device is going
-                * to be resetted
+                * to be resetted. Actually, since we can be in RESET TM
+                * function, it might be dangerous.
                 */
        }
 
        dev->dev_double_ua_possible = 1;
        dev->dev_serialized = 1;
 
-       /* BH already off */
-       spin_lock(&scst_temp_UA_lock);
-       scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
-               SCST_LOAD_SENSE(scst_sense_reset_UA));
-       __scst_process_UA(dev, exclude_cmd, scst_temp_UA, sizeof(scst_temp_UA),
-               1);
-       spin_unlock(&scst_temp_UA_lock);
-
        list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, 
-               dev_tgt_dev_list_entry) 
-       {
+               dev_tgt_dev_list_entry) {
                struct scst_session *sess = tgt_dev->sess;
 
+               spin_lock_bh(&tgt_dev->tgt_dev_lock);
+               scst_free_all_UA(tgt_dev);
+               spin_unlock_bh(&tgt_dev->tgt_dev_lock);
+
                spin_lock_irq(&sess->sess_list_lock);
 
                TRACE_DBG("Searching in search cmd list (sess=%p)", sess);
@@ -2245,8 +2377,8 @@ void scst_process_reset(struct scst_device *dev,
                        if ((cmd->tgt_dev == tgt_dev) ||
                            ((cmd->tgt_dev == NULL) && 
                             (cmd->lun == tgt_dev->lun))) {
-                               scst_abort_cmd(cmd, mcmd, 
-                                       (tgt_dev->sess != originator), 0);
+                               scst_abort_cmd(cmd, mcmd,
+                                       (tgt_dev->sess != originator), 0);
                        }
                }
                spin_unlock_irq(&sess->sess_list_lock);
@@ -2266,6 +2398,14 @@ void scst_process_reset(struct scst_device *dev,
                }
        }
 
+       /* BH already off */
+       spin_lock(&scst_temp_UA_lock);
+       scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
+               SCST_LOAD_SENSE(scst_sense_reset_UA));
+       scst_dev_check_set_local_UA(dev, exclude_cmd, scst_temp_UA,
+               sizeof(scst_temp_UA));
+       spin_unlock(&scst_temp_UA_lock);
+
        TRACE_EXIT();
        return;
 }
@@ -2322,7 +2462,7 @@ out_unlock:
 
 /* Called under dev_lock, tgt_dev_lock and BH off */
 void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
-       const uint8_t *sense, int sense_len)
+       const uint8_t *sense, int sense_len, int head)
 {
        struct scst_tgt_dev_UA *UA_entry = NULL;
 
@@ -2342,16 +2482,21 @@ void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
        memcpy(UA_entry->UA_sense_buffer, sense, sense_len);
        set_bit(SCST_TGT_DEV_UA_PENDING, &tgt_dev->tgt_dev_flags);
        smp_mb__after_set_bit();
-       list_add_tail(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
+
+       TRACE_MGMT_DBG("Adding new UA to tgt_dev %p", tgt_dev);
+
+       if (head)
+               list_add(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
+       else
+               list_add_tail(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
 
 out:
        TRACE_EXIT();
        return;
 }
 
-/* Called under dev_lock and BH off */
 void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
-       const uint8_t *sense, int sense_len)
+       const uint8_t *sense, int sense_len, int head)
 {
        int skip_UA = 0;
        struct scst_tgt_dev_UA *UA_entry_tmp;
@@ -2361,16 +2506,16 @@ void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
        spin_lock(&tgt_dev->tgt_dev_lock);
 
        list_for_each_entry(UA_entry_tmp, &tgt_dev->UA_list,
-                           UA_list_entry) 
-       {
-               if (sense[12] == UA_entry_tmp->UA_sense_buffer[12]) {
+                           UA_list_entry) {
+               if (memcmp(sense, UA_entry_tmp->UA_sense_buffer, sense_len) == 0) {
+                       TRACE_MGMT_DBG("%s", "UA already exists");
                        skip_UA = 1;
                        break;
                }
        }
 
        if (skip_UA == 0)
-               scst_alloc_set_UA(tgt_dev, sense, sense_len);
+               scst_alloc_set_UA(tgt_dev, sense, sense_len, head);
 
        spin_unlock(&tgt_dev->tgt_dev_lock);
 
@@ -2378,31 +2523,41 @@ void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
        return;
 }
 
-/* Called under dev_lock and BH off */
-void __scst_process_UA(struct scst_device *dev,
-       struct scst_cmd *exclude, const uint8_t *sense, int sense_len,
-       int internal)
+/* No locks, but the activity must not get suspended while inside this function */
+void scst_dev_check_set_local_UA(struct scst_device *dev,
+       struct scst_cmd *exclude, const uint8_t *sense, int sense_len)
 {
        struct scst_tgt_dev *tgt_dev, *exclude_tgt_dev = NULL;
 
        TRACE_ENTRY();
 
-       TRACE(TRACE_MGMT, "Processing UA dev %p", dev);
-
        if (exclude != NULL)
                exclude_tgt_dev = exclude->tgt_dev;
 
+       list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, 
+                       dev_tgt_dev_list_entry) {
+               if (tgt_dev != exclude_tgt_dev)
+                       scst_check_set_UA(tgt_dev, sense, sense_len, 0);
+       }
+
+       TRACE_EXIT();
+       return;
+}
+
+/* Called under dev_lock and BH off */
+void __scst_dev_check_set_UA(struct scst_device *dev,
+       struct scst_cmd *exclude, const uint8_t *sense, int sense_len)
+{
+       TRACE_ENTRY();
+
+       TRACE(TRACE_MGMT, "Processing UA dev %p", dev);
+
        /* Check for reset UA */
-       if (!internal && (sense[12] == SCST_SENSE_ASC_UA_RESET)) {
+       if (sense[12] == SCST_SENSE_ASC_UA_RESET)
                scst_process_reset(dev, (exclude != NULL) ? exclude->sess : NULL,
                        exclude, NULL);
-       }
 
-       list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, 
-                               dev_tgt_dev_list_entry) {
-               if (tgt_dev != exclude_tgt_dev)
-                       scst_check_set_UA(tgt_dev, sense, sense_len);
-       }
+       scst_dev_check_set_local_UA(dev, exclude, sense, sense_len);
 
        TRACE_EXIT();
        return;
@@ -2817,6 +2972,72 @@ out:
        return;
 }
 
+void scst_on_hq_cmd_response(struct scst_cmd *cmd)
+{
+       struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
+
+       TRACE_ENTRY();
+
+       spin_lock_irq(&tgt_dev->sn_lock);
+       tgt_dev->hq_cmd_count--;
+       spin_unlock_irq(&tgt_dev->sn_lock);
+
+       EXTRACHECKS_BUG_ON(tgt_dev->hq_cmd_count < 0);
+
+       /*
+        * There is no problem in checking hq_cmd_count in the
+        * non-locked state. In the worst case we will only have
+        * unneeded run of the deferred commands.
+        */
+       if (tgt_dev->hq_cmd_count == 0) {
+               struct scst_cmd *c =
+                       scst_check_deferred_commands(tgt_dev);
+               if (c != NULL) {
+                       spin_lock_irq(&c->cmd_lists->cmd_list_lock);
+                       TRACE_SN("Adding cmd %p to active cmd list", c);
+                       list_add_tail(&c->cmd_list_entry,
+                               &c->cmd_lists->active_cmd_list);
+                       wake_up(&c->cmd_lists->cmd_list_waitQ);
+                       spin_unlock_irq(&c->cmd_lists->cmd_list_lock);
+               }
+       }
+
+       TRACE_EXIT();
+       return;
+}
+
+void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd)
+{
+       TRACE_ENTRY();
+
+       if (test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags)) {
+               if (cmd->completed) {
+                       /* 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) {
+                       scst_set_cmd_error_status(cmd, SAM_STAT_TASK_ABORTED);
+               } else {
+                       /* Abort without delivery or notification */
+                       clear_bit(SCST_CMD_ABORTED_OTHER,
+                               &cmd->cmd_flags);
+               }
+       } else {
+               if ((cmd->tgt_dev != NULL) &&
+                   scst_is_ua_sense(cmd->sense_buffer)) {
+                       /* This UA delivery is going to fail, so requeue it */
+                       scst_check_set_UA(cmd->tgt_dev, cmd->sense_buffer,
+                                       sizeof(cmd->sense_buffer), 1);
+               }
+       }
+
+out:
+       TRACE_EXIT();
+       return;
+}
+
 void __init scst_scsi_op_list_init(void)
 {
        int i;
@@ -3095,6 +3316,15 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
                                "delayed cmd %p (tag=%llu), moving it to "
                                "active cmd list (delayed_cmds_count=%d)",
                                c, c->tag, tm_dbg_delayed_cmds_count);
+
+                       if (!test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags)) {
+                               if (((scst_random() % 10) == 5)) {
+                                       scst_set_cmd_error(cmd,
+                                          SCST_LOAD_SENSE(scst_sense_hardw_error));
+                                       /* It's completed now */
+                               }
+                       }
+
                        spin_lock(&cmd->cmd_lists->cmd_list_lock);
                        list_move(&c->cmd_list_entry, 
                                &c->cmd_lists->active_cmd_list);
index c474ae7..3172994 100644 (file)
@@ -509,6 +509,10 @@ static int scst_register_device(struct scsi_device *scsidp)
        dev->scsi_dev = scsidp;
 
        list_add_tail(&dev->dev_list_entry, &scst_dev_list);
+
+       res = scst_obtain_device_parameters(dev);
+       if (res != 0)
+               goto out_free;
        
        list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
                if (dt->type == scsidp->type) {
@@ -710,12 +714,12 @@ void scst_unregister_virtual_device(int id)
        list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
                if (d->virt_id == id) {
                        dev = d;
-                       TRACE_DBG("Target device %p found", dev);
+                       TRACE_DBG("Target device %p (id %d) found", dev, id);
                        break;
                }
        }
        if (dev == NULL) {
-               PRINT_ERROR("%s", "Target device not found");
+               PRINT_ERROR("Target virtual device (id %d) not found", id);
                goto out_unblock;
        }
 
@@ -1672,6 +1676,8 @@ EXPORT_SYMBOL(scst_set_busy);
 EXPORT_SYMBOL(scst_set_cmd_error_status);
 EXPORT_SYMBOL(scst_set_cmd_error);
 EXPORT_SYMBOL(scst_set_resp_data_len);
+EXPORT_SYMBOL(scst_set_sense);
+EXPORT_SYMBOL(scst_set_cmd_error_sense);
 
 EXPORT_SYMBOL(scst_process_active_cmd);
 
index 478b0a3..7c0f5d1 100644 (file)
@@ -56,7 +56,7 @@ extern unsigned long scst_trace_flag;
 */
 #define SCST_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
        TRACE_LINE | TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | \
-       TRACE_MGMT_DEBUG | TRACE_RETRY)
+       TRACE_MGMT_MINOR | TRACE_MGMT_DEBUG | TRACE_RETRY)
 
 #define TRACE_SN(args...)      TRACE(TRACE_SCSI_SERIALIZING, args)
 
@@ -103,7 +103,7 @@ extern unsigned long scst_trace_flag;
  ** Maximum count of uncompleted commands that an initiator could 
  ** queue on any device. Then it will start getting TASK QUEUE FULL status.
  **/
-#define SCST_MAX_TGT_DEV_COMMANDS            64
+#define SCST_MAX_TGT_DEV_COMMANDS            32
 
 /**
  ** Maximum count of uncompleted commands that could be queued on any device.
@@ -115,7 +115,8 @@ extern unsigned long scst_trace_flag;
 #define SCST_TGT_RETRY_TIMEOUT               (3/2*HZ)
 #define SCST_CMD_MEM_TIMEOUT                 (120*HZ)
 
-static inline int scst_get_context(void) {
+static inline int scst_get_context(void)
+{
        if (in_irq())
                return SCST_CONTEXT_TASKLET;
        if (irqs_disabled())
@@ -234,6 +235,9 @@ int scst_check_hq_cmd(struct scst_cmd *cmd);
 void scst_unblock_deferred(struct scst_tgt_dev *tgt_dev,
        struct scst_cmd *cmd_sn);
 
+void scst_on_hq_cmd_response(struct scst_cmd *cmd);
+void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd);
+
 int scst_cmd_thread(void *arg);
 void scst_cmd_tasklet(long p);
 int scst_init_cmd_thread(void *arg);
@@ -254,7 +258,7 @@ void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
 
 int scst_sess_alloc_tgt_devs(struct scst_session *sess);
 void scst_sess_free_tgt_devs(struct scst_session *sess);
-void scst_reset_tgt_dev(struct scst_tgt_dev *tgt_dev, int nexus_loss);
+void scst_nexus_loss(struct scst_tgt_dev *tgt_dev);
 
 int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun,
        int read_only);
@@ -350,23 +354,26 @@ void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type);
 
 int scst_get_cdb_len(const uint8_t *cdb);
 
-void __scst_process_UA(struct scst_device *dev, struct scst_cmd *exclude,
-       const uint8_t *sense, int sense_len, int internal);
-static inline void scst_process_UA(struct scst_device *dev,
-       struct scst_cmd *exclude, const uint8_t *sense, int sense_len,
-       int internal)
+int scst_obtain_device_parameters(struct scst_device *dev);
+
+void __scst_dev_check_set_UA(struct scst_device *dev, struct scst_cmd *exclude,
+       const uint8_t *sense, int sense_len);
+static inline void scst_dev_check_set_UA(struct scst_device *dev,
+       struct scst_cmd *exclude, const uint8_t *sense, int sense_len)
 {
        spin_lock_bh(&dev->dev_lock);
-       __scst_process_UA(dev, exclude, sense, sense_len, internal);
+       __scst_dev_check_set_UA(dev, exclude, sense, sense_len);
        spin_unlock_bh(&dev->dev_lock);
        return;
 }
-void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev, const uint8_t *sense,
-       int sense_len);
+void scst_dev_check_set_local_UA(struct scst_device *dev,
+       struct scst_cmd *exclude, const uint8_t *sense, int sense_len);
 void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
-       const uint8_t *sense, int sense_len);
-int scst_set_pending_UA(struct scst_cmd *cmd);
+       const uint8_t *sense, int sense_len, int head);
+void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev, const uint8_t *sense,
+       int sense_len, int head);
 void scst_free_all_UA(struct scst_tgt_dev *tgt_dev);
+int scst_set_pending_UA(struct scst_cmd *cmd);
 
 void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
        int other_ini, int call_dev_task_mgmt_fn);
@@ -487,19 +494,6 @@ static inline void scst_cmd_put(struct scst_cmd *cmd)
 extern void scst_throttle_cmd(struct scst_cmd *cmd);
 extern void scst_unthrottle_cmd(struct scst_cmd *cmd);
 
-static inline void scst_set_sense(uint8_t *buffer, int len, int key,
-       int asc, int ascq)
-{
-       memset(buffer, 0, len);
-       buffer[0] = 0x70;       /* Error Code                   */
-       buffer[2] = key;        /* Sense Key                    */
-       buffer[7] = 0x0a;       /* Additional Sense Length      */
-       buffer[12] = asc;       /* ASC                          */
-       buffer[13] = ascq;      /* ASCQ                         */
-       TRACE_BUFFER("Sense set", buffer, len);
-       return;
-}
-
 static inline void scst_check_restore_sg_buff(struct scst_cmd *cmd)
 {
        if (cmd->sg_buff_modified) {
index 8a0bb4f..defc373 100644 (file)
@@ -101,6 +101,7 @@ static struct scst_proc_log scst_proc_trace_tbl[] =
     { TRACE_SPECIAL,           "special" },
     { TRACE_SCSI,              "scsi" },
     { TRACE_MGMT,              "mgmt" },
+    { TRACE_MGMT_MINOR,                "mgmt_minor" },
     { TRACE_MGMT_DEBUG,                "mgmt_dbg" },
     { 0,                       NULL }
 };
index 23bbedc..d2d617d 100644 (file)
@@ -74,7 +74,6 @@ struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
        cmd->sess = sess;
        cmd->tgt = sess->tgt;
        cmd->tgtt = sess->tgt->tgtt;
-       cmd->state = SCST_CMD_STATE_INIT_WAIT;
 
        /* 
         * For both wrong lun and CDB defer the error reporting for
@@ -142,7 +141,7 @@ out_redirect:
                 */
                sBUG_ON(context != SCST_CONTEXT_DIRECT);
                scst_set_busy(cmd);
-               cmd->state = SCST_CMD_STATE_XMIT_RESP;
+               cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
                /* Keep initiator away from too many BUSY commands */
                if (!in_interrupt() && !in_atomic())
                        msleep(50);
@@ -206,7 +205,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd, int pref_context)
                case SCST_SESS_IPH_FAILED:
                        spin_unlock_irqrestore(&sess->sess_list_lock, flags);
                        scst_set_busy(cmd);
-                       cmd->state = SCST_CMD_STATE_XMIT_RESP;
+                       cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
                        goto active;
                default:
                        sBUG();
@@ -219,7 +218,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd, int pref_context)
                PRINT_ERROR("Wrong LUN %d, finishing cmd", -1);
                scst_set_cmd_error(cmd,
                        SCST_LOAD_SENSE(scst_sense_lun_not_supported));
-               cmd->state = SCST_CMD_STATE_XMIT_RESP;
+               cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
                goto active;
        }
 
@@ -227,7 +226,15 @@ void scst_cmd_init_done(struct scst_cmd *cmd, int pref_context)
                PRINT_ERROR("Wrong CDB len %d, finishing cmd", 0);
                scst_set_cmd_error(cmd,
                           SCST_LOAD_SENSE(scst_sense_invalid_opcode));
-               cmd->state = SCST_CMD_STATE_XMIT_RESP;
+               cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
+               goto active;
+       }
+
+       if (unlikely(cmd->queue_type >= SCST_CMD_QUEUE_ACA)) {
+               PRINT_ERROR("Unsupported queue type %d", cmd->queue_type);
+               scst_set_cmd_error(cmd,
+                       SCST_LOAD_SENSE(scst_sense_invalid_message));
+               cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
                goto active;
        }
 
@@ -273,29 +280,17 @@ out:
        return;
 }
 
-static int scst_parse_cmd(struct scst_cmd *cmd)
+static int scst_pre_parse(struct scst_cmd *cmd)
 {
        int res = SCST_CMD_STATE_RES_CONT_SAME;
-       int state;
        struct scst_device *dev = cmd->dev;
        struct scst_info_cdb cdb_info;
-       int atomic = scst_cmd_atomic(cmd);
-       int orig_bufflen;
 
        TRACE_ENTRY();
 
-       if (atomic && !dev->handler->parse_atomic) {
-               TRACE_DBG("Dev handler %s parse() can not be "
-                     "called in atomic context, rescheduling to the thread",
-                     dev->handler->name);
-               res = SCST_CMD_STATE_RES_NEED_THREAD;
-               goto out;
-       }
-
-       cmd->inc_expected_sn_on_done = dev->handler->inc_expected_sn_on_done;
+       cmd->inc_expected_sn_on_done = !dev->has_own_order_mgmt;
 
-       if (cmd->skip_parse || cmd->internal)
-               goto call_parse;
+       sBUG_ON(cmd->internal);
 
        /*
         * Expected transfer data supplied by the SCSI transport via the
@@ -388,7 +383,37 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
                goto out_xmit;
        }
 
-call_parse:
+       cmd->state = SCST_CMD_STATE_DEV_PARSE;
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+
+out_xmit:
+       cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
+       res = SCST_CMD_STATE_RES_CONT_SAME;
+       goto out;
+}
+
+static int scst_parse_cmd(struct scst_cmd *cmd)
+{
+       int res = SCST_CMD_STATE_RES_CONT_SAME;
+       int state;
+       struct scst_device *dev = cmd->dev;
+       struct scst_info_cdb cdb_info;
+       int atomic = scst_cmd_atomic(cmd);
+       int orig_bufflen;
+
+       TRACE_ENTRY();
+
+       if (atomic && !dev->handler->parse_atomic) {
+               TRACE_DBG("Dev handler %s parse() can not be "
+                     "called in atomic context, rescheduling to the thread",
+                     dev->handler->name);
+               res = SCST_CMD_STATE_RES_NEED_THREAD;
+               goto out;
+       }
+
        orig_bufflen = cmd->bufflen;
 
        if (likely(!scst_is_cmd_local(cmd))) {
@@ -429,7 +454,7 @@ call_parse:
                goto out_error;
        }
 
-       if (unlikely(state == SCST_CMD_STATE_XMIT_RESP))
+       if (unlikely(state == SCST_CMD_STATE_PRE_XMIT_RESP))
                goto set_res;
 
 #ifdef EXTRACHECKS
@@ -473,11 +498,13 @@ call_parse:
                if (unlikely(cmd->bufflen != cmd->expected_transfer_len)) {
                        PRINT_INFO("Warning: expected transfer length %d for "
                                "opcode 0x%02x (handler %s, target %s) doesn't "
-                               "match decoded value %d. Faulty initiator or "
+                               "match decoded value %d. Faulty initiator "
+                               "(e.g. VMware is known to be such) or "
                                "scst_scsi_op_table should be updated?",
                                cmd->expected_transfer_len, cmd->cdb[0],
                                dev->handler->name, cmd->tgtt->name,
                                cmd->bufflen);
+                       PRINT_BUFFER("Suspicious CDB", cmd->cdb, cmd->cdb_len);
                }
 #endif
        }
@@ -494,11 +521,14 @@ call_parse:
 set_res:
        switch (state) {
        case SCST_CMD_STATE_PREPARE_SPACE:
+       case SCST_CMD_STATE_PRE_PARSE:
        case SCST_CMD_STATE_DEV_PARSE:
        case SCST_CMD_STATE_RDY_TO_XFER:
-       case SCST_CMD_STATE_PRE_EXEC:
+       case SCST_CMD_STATE_TGT_PRE_EXEC:
        case SCST_CMD_STATE_SEND_TO_MIDLEV:
+       case SCST_CMD_STATE_PRE_DEV_DONE:
        case SCST_CMD_STATE_DEV_DONE:
+       case SCST_CMD_STATE_PRE_XMIT_RESP:
        case SCST_CMD_STATE_XMIT_RESP:
        case SCST_CMD_STATE_FINISHED:
                cmd->state = state;
@@ -536,12 +566,7 @@ out_error:
 #ifndef USE_EXPECTED_VALUES
 out_dev_done:
 #endif
-       cmd->state = SCST_CMD_STATE_DEV_DONE;
-       res = SCST_CMD_STATE_RES_CONT_SAME;
-       goto out;
-
-out_xmit:
-       cmd->state = SCST_CMD_STATE_XMIT_RESP;
+       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
        res = SCST_CMD_STATE_RES_CONT_SAME;
        goto out;
 }
@@ -608,7 +633,7 @@ prep_done:
                if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
                        TRACE_MGMT_DBG("ABORTED set, returning ABORTED for "
                                "cmd %p", cmd);
-                       cmd->state = SCST_CMD_STATE_DEV_DONE;
+                       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                        res = SCST_CMD_STATE_RES_CONT_SAME;
                        goto out;
                }
@@ -629,7 +654,7 @@ prep_done:
                break;
 
        default:
-               cmd->state = SCST_CMD_STATE_PRE_EXEC;
+               cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
                break;
        }
 
@@ -641,13 +666,13 @@ out_no_space:
        TRACE(TRACE_OUT_OF_MEM, "Unable to allocate or build requested buffer "
                "(size %d), sending BUSY or QUEUE FULL status", cmd->bufflen);
        scst_set_busy(cmd);
-       cmd->state = SCST_CMD_STATE_DEV_DONE;
+       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
        res = SCST_CMD_STATE_RES_CONT_SAME;
        goto out;
 
 out_error:
        scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
-       cmd->state = SCST_CMD_STATE_DEV_DONE;
+       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
        res = SCST_CMD_STATE_RES_CONT_SAME;
        goto out;
 }
@@ -677,7 +702,7 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status, int pref_context)
                        cmd->state = SCST_CMD_STATE_RDY_TO_XFER;
                        break;
                default:
-                       cmd->state = SCST_CMD_STATE_PRE_EXEC;
+                       cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
                        break;
                }
                if (cmd->set_sn_on_restart_cmd)
@@ -698,7 +723,7 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status, int pref_context)
                break;
 
        case SCST_PREPROCESS_STATUS_ERROR_SENSE_SET:
-               cmd->state = SCST_CMD_STATE_DEV_DONE;
+               cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                break;
 
        case SCST_PREPROCESS_STATUS_ERROR_FATAL:
@@ -707,13 +732,13 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status, int pref_context)
        case SCST_PREPROCESS_STATUS_ERROR:
                scst_set_cmd_error(cmd,
                           SCST_LOAD_SENSE(scst_sense_hardw_error));
-               cmd->state = SCST_CMD_STATE_DEV_DONE;
+               cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                break;
 
        default:
                PRINT_ERROR("%s() received unknown status %x", __func__,
                        status);
-               cmd->state = SCST_CMD_STATE_DEV_DONE;
+               cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                break;
        }
 
@@ -740,7 +765,7 @@ static int scst_queue_retry_cmd(struct scst_cmd *cmd, int finished_cmds)
        if (finished_cmds != atomic_read(&tgt->finished_cmds)) {
                /* At least one cmd finished, so try again */
                tgt->retry_cmds--;
-               TRACE(TRACE_RETRY, "TGT QUEUE FULL, direct retry "
+               TRACE(TRACE_RETRY, "Some command(s) finished, direct retry "
                      "(finished_cmds=%d, tgt->finished_cmds=%d, "
                      "retry_cmds=%d)", finished_cmds,
                      atomic_read(&tgt->finished_cmds), tgt->retry_cmds);
@@ -777,7 +802,7 @@ static int scst_rdy_to_xfer(struct scst_cmd *cmd)
        }
 
        if (cmd->tgtt->rdy_to_xfer == NULL) {
-               cmd->state = SCST_CMD_STATE_PRE_EXEC;
+               cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
                res = SCST_CMD_STATE_RES_CONT_SAME;
                goto out;
        }
@@ -812,21 +837,17 @@ static int scst_rdy_to_xfer(struct scst_cmd *cmd)
 
                switch (rc) {
                case SCST_TGT_RES_QUEUE_FULL:
-               {
                        if (scst_queue_retry_cmd(cmd, finished_cmds) == 0)
                                break;
                        else
                                continue;
-               }
 
                case SCST_TGT_RES_NEED_THREAD_CTX:
-               {
                        TRACE_DBG("Target driver %s "
                              "rdy_to_xfer() requested thread "
                              "context, rescheduling", cmd->tgtt->name);
                        res = SCST_CMD_STATE_RES_NEED_THREAD;
                        break;
-               }
 
                default:
                        goto out_error_rc;
@@ -849,7 +870,7 @@ out_error_rc:
        scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
 
 out_dev_done:
-       cmd->state = SCST_CMD_STATE_DEV_DONE;
+       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
        res = SCST_CMD_STATE_RES_CONT_SAME;
        goto out;
 }
@@ -922,7 +943,7 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context)
 
        switch (status) {
        case SCST_RX_STATUS_SUCCESS:
-               cmd->state = SCST_CMD_STATE_PRE_EXEC;
+               cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
                /* Small context optimization */
                if ((pref_context == SCST_CONTEXT_TASKLET) || 
                    (pref_context == SCST_CONTEXT_DIRECT_ATOMIC)) {
@@ -933,7 +954,7 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context)
                break;
 
        case SCST_RX_STATUS_ERROR_SENSE_SET:
-               cmd->state = SCST_CMD_STATE_DEV_DONE;
+               cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                break;
 
        case SCST_RX_STATUS_ERROR_FATAL:
@@ -942,13 +963,13 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context)
        case SCST_RX_STATUS_ERROR:
                scst_set_cmd_error(cmd,
                           SCST_LOAD_SENSE(scst_sense_hardw_error));
-               cmd->state = SCST_CMD_STATE_DEV_DONE;
+               cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                break;
 
        default:
                PRINT_ERROR("scst_rx_data() received unknown status %x",
                        status);
-               cmd->state = SCST_CMD_STATE_DEV_DONE;
+               cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                break;
        }
 
@@ -960,7 +981,7 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context)
 
 static int scst_tgt_pre_exec(struct scst_cmd *cmd)
 {
-       int rc;
+       int res = SCST_CMD_STATE_RES_CONT_SAME, rc;
 
        TRACE_ENTRY();
 
@@ -976,7 +997,7 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
        if (unlikely(rc != SCST_PREPROCESS_STATUS_SUCCESS)) {
                switch(rc) {
                case SCST_PREPROCESS_STATUS_ERROR_SENSE_SET:
-                       cmd->state = SCST_CMD_STATE_DEV_DONE;
+                       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                        break;
                case SCST_PREPROCESS_STATUS_ERROR_FATAL:
                        set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
@@ -984,7 +1005,13 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
                case SCST_PREPROCESS_STATUS_ERROR:
                        scst_set_cmd_error(cmd,
                                   SCST_LOAD_SENSE(scst_sense_hardw_error));
-                       cmd->state = SCST_CMD_STATE_DEV_DONE;
+                       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
+                       break;
+               case SCST_PREPROCESS_STATUS_NEED_THREAD:
+                       TRACE_DBG("Target driver's %s pre_exec() requested "
+                               "thread context, rescheduling", cmd->tgtt->name);
+                       res = SCST_CMD_STATE_RES_NEED_THREAD;
+                       cmd->state = SCST_CMD_STATE_TGT_PRE_EXEC;
                        break;
                default:
                        sBUG();
@@ -993,39 +1020,15 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
        }
 
 out:
-       TRACE_EXIT();
-       return SCST_CMD_STATE_RES_CONT_SAME;
-}
-
-static void scst_inc_check_expected_sn(struct scst_cmd *cmd)
-{
-       struct scst_cmd *c;
-
-       if (likely(cmd->sn_set))
-               scst_inc_expected_sn(cmd->tgt_dev, cmd->sn_slot);
-
-       c = scst_check_deferred_commands(cmd->tgt_dev);
-       if (c != NULL) {
-               unsigned long flags;
-               spin_lock_irqsave(&c->cmd_lists->cmd_list_lock, flags);
-               TRACE_SN("Adding cmd %p to active cmd list", c);
-               list_add_tail(&c->cmd_list_entry,
-                       &c->cmd_lists->active_cmd_list);
-               wake_up(&c->cmd_lists->cmd_list_waitQ);
-               spin_unlock_irqrestore(&c->cmd_lists->cmd_list_lock, flags);
-       }
+       TRACE_EXIT_RES(res);
+       return res;
 }
 
 static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
        const uint8_t *rq_sense, int rq_sense_len, int resid)
 {
-       unsigned char type;
-
        TRACE_ENTRY();
 
-       if (cmd->inc_expected_sn_on_done)
-               scst_inc_check_expected_sn(cmd);
-
        cmd->status = result & 0xff;
        cmd->msg_status = msg_byte(result);
        cmd->host_status = host_byte(result);
@@ -1033,8 +1036,9 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
        if (unlikely(resid != 0)) {
 #ifdef EXTRACHECKS
                if ((resid < 0) || (resid > cmd->resp_data_len)) {
-                       PRINT_ERROR("Wrong resid %d (cmd->resp_data_len=%d)",
-                               resid, cmd->resp_data_len);
+                       PRINT_ERROR("Wrong resid %d (cmd->resp_data_len=%d, "
+                               "op %x)", resid, cmd->resp_data_len,
+                               cmd->cdb[0]);
                } else
 #endif
                        scst_set_resp_data_len(cmd, cmd->resp_data_len - resid);
@@ -1055,35 +1059,6 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
 
        cmd->completed = 1;
 
-       if (likely(cmd->host_status != DID_RESET) &&
-           likely(!SCST_SENSE_VALID(cmd->sense_buffer)))
-               scst_dec_on_dev_cmd(cmd);
-
-       type = cmd->dev->handler->type;
-       if ((cmd->cdb[0] == MODE_SENSE || cmd->cdb[0] == MODE_SENSE_10) &&
-           cmd->tgt_dev->acg_dev->rd_only_flag &&
-           (type == TYPE_DISK || type == TYPE_WORM || type == TYPE_MOD ||
-            type == TYPE_TAPE)) {
-               int32_t length;
-               uint8_t *address;
-
-               length = scst_get_buf_first(cmd, &address);
-               TRACE_DBG("length %d", length);
-               if (unlikely(length <= 0)) {
-                       PRINT_ERROR("%s: scst_get_buf_first() failed",
-                               __func__);
-                       goto out;
-               }
-               if (length > 2 && cmd->cdb[0] == MODE_SENSE) {
-                       address[2] |= 0x80;   /* Write Protect*/
-               }
-               else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10) {
-                       address[3] |= 0x80;   /* Write Protect*/
-               }
-               scst_put_buf(cmd, address);
-       }
-
-out:
        TRACE_EXIT();
        return;
 }
@@ -1143,7 +1118,7 @@ static void scst_cmd_done(struct scsi_cmnd *scsi_cmd)
 
        scst_release_request(cmd);
 
-       cmd->state = SCST_CMD_STATE_DEV_DONE;
+       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
 
        scst_proccess_redirect_cmd(cmd,
                scst_optimize_post_exec_context(cmd, scst_get_context()), 0);
@@ -1165,7 +1140,7 @@ static void scst_cmd_done(void *data, char *sense, int result, int resid)
 
        scst_do_cmd_done(cmd, result, sense, SCST_SENSE_BUFFERSIZE, resid);
 
-       cmd->state = SCST_CMD_STATE_DEV_DONE;
+       cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
 
        scst_proccess_redirect_cmd(cmd,
                scst_optimize_post_exec_context(cmd, scst_get_context()), 0);
@@ -1180,17 +1155,11 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
 {
        TRACE_ENTRY();
 
-       if (likely(!SCST_SENSE_VALID(cmd->sense_buffer)))
-               scst_dec_on_dev_cmd(cmd);
-
-       if (cmd->inc_expected_sn_on_done)
-               scst_inc_check_expected_sn(cmd);
-
        if (next_state == SCST_CMD_STATE_DEFAULT)
-               next_state = SCST_CMD_STATE_DEV_DONE;
+               next_state = SCST_CMD_STATE_PRE_DEV_DONE;
 
 #if defined(DEBUG) || defined(TRACING)
-       if (next_state == SCST_CMD_STATE_DEV_DONE) {
+       if (next_state == SCST_CMD_STATE_PRE_DEV_DONE) {
                if (cmd->sg) {
                        int i;
                        struct scatterlist *sg = cmd->sg;
@@ -1208,15 +1177,15 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
 
 
 #ifdef EXTRACHECKS
-       if ((next_state != SCST_CMD_STATE_DEV_DONE) &&
-           (next_state != SCST_CMD_STATE_XMIT_RESP) &&
+       if ((next_state != SCST_CMD_STATE_PRE_DEV_DONE) &&
+           (next_state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
            (next_state != SCST_CMD_STATE_FINISHED)) 
        {
                PRINT_ERROR("scst_cmd_done_local() received invalid cmd "
                            "state %d (opcode %d)", next_state, cmd->cdb[0]);
                scst_set_cmd_error(cmd,
                                   SCST_LOAD_SENSE(scst_sense_hardw_error));
-               next_state = SCST_CMD_STATE_DEV_DONE;
+               next_state = SCST_CMD_STATE_PRE_DEV_DONE;
        }
 #endif
        cmd->state = next_state;
@@ -1351,6 +1320,11 @@ static int scst_pre_select(struct scst_cmd *cmd)
                goto out;
        }
 
+       if (cmd->local_exec_done)
+               goto out;
+
+       cmd->local_exec_done = 1;
+
        scst_block_dev_cmd(cmd, 1);
 
        /* Check for local events will be done when cmd will be executed */
@@ -1362,7 +1336,7 @@ out:
 
 static int scst_reserve_local(struct scst_cmd *cmd)
 {
-       int res, rc;
+       int res = SCST_EXEC_NOT_COMPLETED, rc;
        struct scst_device *dev;
        struct scst_tgt_dev *tgt_dev_tmp;
 
@@ -1373,12 +1347,17 @@ static int scst_reserve_local(struct scst_cmd *cmd)
                goto out;
        }
 
+       if (cmd->local_exec_done)
+               goto out;
+
+       cmd->local_exec_done = 1;
+
        if ((cmd->cdb[0] == RESERVE_10) && (cmd->cdb[2] & SCST_RES_3RDPTY)) {
                PRINT_ERROR("RESERVE_10: 3rdPty RESERVE not implemented "
                     "(lun=%Ld)", (uint64_t)cmd->lun);
                scst_set_cmd_error(cmd,
                        SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
-               goto out_compl;
+               goto out_done;
        }
 
        dev = cmd->dev;
@@ -1394,7 +1373,7 @@ static int scst_reserve_local(struct scst_cmd *cmd)
        if (test_bit(SCST_TGT_DEV_RESERVED, &cmd->tgt_dev->tgt_dev_flags)) {
                spin_unlock_bh(&dev->dev_lock);
                scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT);
-               goto out_compl;
+               goto out_done;
        }
 
        list_for_each_entry(tgt_dev_tmp, &dev->dev_tgt_dev_list,
@@ -1406,17 +1385,12 @@ static int scst_reserve_local(struct scst_cmd *cmd)
        }
        dev->dev_reserved = 1;
 
-       res = SCST_EXEC_NOT_COMPLETED;
-
        spin_unlock_bh(&dev->dev_lock);
        
 out:
        TRACE_EXIT_RES(res);
        return res;
 
-out_compl:
-       cmd->completed = 1;
-
 out_done:
        /* Report the result */
        scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
@@ -1426,7 +1400,7 @@ out_done:
 
 static int scst_release_local(struct scst_cmd *cmd)
 {
-       int res, rc;
+       int res = SCST_EXEC_NOT_COMPLETED, rc;
        struct scst_tgt_dev *tgt_dev_tmp;
        struct scst_device *dev;
 
@@ -1437,6 +1411,11 @@ static int scst_release_local(struct scst_cmd *cmd)
                goto out;
        }
 
+       if (cmd->local_exec_done)
+               goto out;
+
+       cmd->local_exec_done = 1;
+
        dev = cmd->dev;
 
        scst_block_dev_cmd(cmd, 1);
@@ -1458,6 +1437,7 @@ static int scst_release_local(struct scst_cmd *cmd)
                cmd->msg_status = 0;
                cmd->host_status = DID_OK;
                cmd->driver_status = 0;
+               cmd->completed = 1;
        } else {
                list_for_each_entry(tgt_dev_tmp,
                                    &dev->dev_tgt_dev_list,
@@ -1471,17 +1451,12 @@ static int scst_release_local(struct scst_cmd *cmd)
        spin_unlock_bh(&dev->dev_lock);
 
        if (res == SCST_EXEC_COMPLETED)
-               goto out_compl;
-
-       res = SCST_EXEC_NOT_COMPLETED;
+               goto out_done;
 
 out:
        TRACE_EXIT_RES(res);
        return res;
 
-out_compl:
-       cmd->completed = 1;
-
 out_done:
        res = SCST_EXEC_COMPLETED;
        /* Report the result */
@@ -1508,18 +1483,16 @@ int scst_check_local_events(struct scst_cmd *cmd)
                    (cmd->cdb[0] != RELEASE) && (cmd->cdb[0] != RELEASE_10) &&
                    (cmd->cdb[0] != REPORT_DEVICE_IDENTIFIER) &&
                    (cmd->cdb[0] != ALLOW_MEDIUM_REMOVAL || (cmd->cdb[4] & 3)) &&
-                   (cmd->cdb[0] != LOG_SENSE) && (cmd->cdb[0] != REQUEST_SENSE))
-               {
+                   (cmd->cdb[0] != LOG_SENSE) && (cmd->cdb[0] != REQUEST_SENSE)) {
                        scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT);
                        goto out_complete;
                }
        }
 
-       /* If we had internal bus reset, set the command error unit attention */
+       /* If we had internal bus reset, set the command error unit attention */
        if ((cmd->dev->scsi_dev != NULL) &&
            unlikely(cmd->dev->scsi_dev->was_reset)) {
-               if (scst_is_ua_command(cmd)) 
-               {
+               if (scst_is_ua_command(cmd)) {
                        struct scst_device *dev = cmd->dev;
                        int done = 0;
                        /* Prevent more than 1 cmd to be triggered by was_reset */
@@ -1543,8 +1516,7 @@ int scst_check_local_events(struct scst_cmd *cmd)
 
        if (unlikely(test_bit(SCST_TGT_DEV_UA_PENDING, 
                        &cmd->tgt_dev->tgt_dev_flags))) {
-               if (scst_is_ua_command(cmd)) 
-               {
+               if (scst_is_ua_command(cmd)) {
                        rc = scst_set_pending_UA(cmd);
                        if (rc == 0)
                                goto out_complete;
@@ -1559,7 +1531,7 @@ out:
 
 out_complete:
        res = 1;
-       cmd->completed = 1;
+       sBUG_ON(!cmd->completed);
        goto out;
 
 out_uncomplete:
@@ -1578,8 +1550,14 @@ static int scst_pre_exec(struct scst_cmd *cmd)
 
        TRACE_ENTRY();
 
+       /*
+        * This function can be called several times for the same cmd, so it
+        * can't change any state in a non-reentrable way or use something
+        * like local_exec_done!!
+        */
+
        /* Check READ_ONLY device status */
-       if (tgt_dev->acg_dev->rd_only_flag &&
+       if (((tgt_dev->acg_dev->rd_only_flag) || cmd->dev->swp) &&
            (cmd->cdb[0] == WRITE_6 ||  /* ToDo: full list of the modify cmds */
             cmd->cdb[0] == WRITE_10 ||
             cmd->cdb[0] == WRITE_12 ||
@@ -1588,8 +1566,7 @@ static int scst_pre_exec(struct scst_cmd *cmd)
             cmd->cdb[0] == WRITE_VERIFY_12 ||
             cmd->cdb[0] == WRITE_VERIFY_16 ||
             (cmd->dev->handler->type == TYPE_TAPE &&
-             (cmd->cdb[0] == ERASE || cmd->cdb[0] == WRITE_FILEMARKS))))
-       {
+             (cmd->cdb[0] == ERASE || cmd->cdb[0] == WRITE_FILEMARKS)))) {
                scst_set_cmd_error(cmd,
                           SCST_LOAD_SENSE(scst_sense_data_protect));
                goto out_done;
@@ -1601,7 +1578,6 @@ out:
 
 out_done:
        res = SCST_EXEC_COMPLETED;
-       cmd->completed = 1;
        /* Report the result */
        scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT);
        goto out;
@@ -1664,9 +1640,6 @@ static int scst_do_send_to_midlev(struct scst_cmd *cmd)
        cmd->state = SCST_CMD_STATE_EXECUTING;
        cmd->scst_cmd_done = scst_cmd_done_local;
 
-       set_bit(SCST_CMD_EXECUTING, &cmd->cmd_flags);
-       smp_mb__after_set_bit();
-
        rc = scst_pre_exec(cmd);
        /* !! At this point cmd, sess & tgt_dev can be already freed !! */
        if (rc != SCST_EXEC_NOT_COMPLETED) {
@@ -1775,7 +1748,6 @@ out_error:
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)        
 out_busy:
        scst_set_busy(cmd);
-       cmd->completed = 1;
        /* go through */
 #endif
 
@@ -1841,9 +1813,6 @@ static int scst_send_to_midlev(struct scst_cmd **active_cmd)
 
        res = SCST_CMD_STATE_RES_CONT_NEXT;
 
-       if (unlikely(scst_inc_on_dev_cmd(cmd) != 0))
-               goto out;
-
        __scst_get(0); /* protect dev & tgt_dev */
 
        if (unlikely(cmd->internal || cmd->retry)) {
@@ -1861,6 +1830,9 @@ static int scst_send_to_midlev(struct scst_cmd **active_cmd)
                }
        }
 
+       if (unlikely(scst_inc_on_dev_cmd(cmd) != 0))
+               goto out_put;
+
        if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
                goto exec;
 
@@ -1882,7 +1854,7 @@ static int scst_send_to_midlev(struct scst_cmd **active_cmd)
                                TRACE_MGMT_DBG("Aborting out of sn cmd %p (tag %llu)",
                                        cmd, cmd->tag);
                                tgt_dev->def_cmd_count--;
-                               cmd->state = SCST_CMD_STATE_DEV_DONE;
+                               cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
                                res = SCST_CMD_STATE_RES_CONT_SAME;
                        } else {
                                TRACE_SN("Deferring cmd %p (sn=%ld, set %d, "
@@ -1941,7 +1913,6 @@ out_put:
        __scst_put();
        /* !! At this point sess, dev and tgt_dev can be already freed !! */
 
-out:
        TRACE_EXIT_HRES(res);
        return res;
 }
@@ -1950,17 +1921,15 @@ out:
 static int scst_check_sense(struct scst_cmd *cmd)
 {
        int res = 0;
-       int sense_valid;
        struct scst_device *dev = cmd->dev;
        int dbl_ua_possible, ua_sent = 0;
 
        TRACE_ENTRY();
 
-       /* If we had internal bus reset behind us, set the command error UA */
+       /* If we had internal bus reset behind us, set the command error UA */
        if ((dev->scsi_dev != NULL) &&
            unlikely(cmd->host_status == DID_RESET) &&
-           scst_is_ua_command(cmd))
-       {
+           scst_is_ua_command(cmd)) {
                TRACE(TRACE_MGMT, "DID_RESET: was_reset=%d host_status=%x",
                      dev->scsi_dev->was_reset, cmd->host_status);
                scst_set_cmd_error(cmd,
@@ -1972,8 +1941,6 @@ static int scst_check_sense(struct scst_cmd *cmd)
                smp_mb();
        }
 
-       sense_valid = SCST_SENSE_VALID(cmd->sense_buffer);
-
        dbl_ua_possible = dev->dev_double_ua_possible;
        TRACE_DBG("cmd %p dbl_ua_possible %d", cmd, dbl_ua_possible);
        if (unlikely(dbl_ua_possible)) {
@@ -1986,18 +1953,19 @@ static int scst_check_sense(struct scst_cmd *cmd)
                        spin_unlock_bh(&dev->dev_lock);
        }
 
-       if (unlikely(sense_valid)) {
+       if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) && 
+           SCST_SENSE_VALID(cmd->sense_buffer)) {
                TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer,
                        sizeof(cmd->sense_buffer));
                /* Check Unit Attention Sense Key */
-               if (cmd->sense_buffer[2] == UNIT_ATTENTION) {
+               if (scst_is_ua_sense(cmd->sense_buffer)) {
                        if (cmd->sense_buffer[12] == SCST_SENSE_ASC_UA_RESET) {
                                if (dbl_ua_possible) {
                                        if (ua_sent) {
-                                               TRACE(TRACE_MGMT, "%s", 
+                                               TRACE(TRACE_MGMT_MINOR, "%s", 
                                                        "Double UA detected");
                                                /* Do retry */
-                                               TRACE(TRACE_MGMT, "Retrying cmd %p "
+                                               TRACE(TRACE_MGMT_MINOR, "Retrying cmd %p "
                                                        "(tag %llu)", cmd, cmd->tag);
                                                cmd->status = 0;
                                                cmd->msg_status = 0;
@@ -2023,13 +1991,13 @@ static int scst_check_sense(struct scst_cmd *cmd)
                        }
                        if (cmd->ua_ignore == 0) {
                                if (unlikely(dbl_ua_possible)) {
-                                       __scst_process_UA(dev, cmd,
+                                       __scst_dev_check_set_UA(dev, cmd,
                                                cmd->sense_buffer,
-                                               sizeof(cmd->sense_buffer), 0);
+                                               sizeof(cmd->sense_buffer));
                                } else {
-                                       scst_process_UA(dev, cmd,
+                                       scst_dev_check_set_UA(dev, cmd,
                                                cmd->sense_buffer,
-                                               sizeof(cmd->sense_buffer), 0);
+                                               sizeof(cmd->sense_buffer));
                                }
                        }
                }
@@ -2062,8 +2030,7 @@ static int scst_check_auto_sense(struct scst_cmd *cmd)
 
        if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) &&
            (!SCST_SENSE_VALID(cmd->sense_buffer) ||
-            SCST_NO_SENSE(cmd->sense_buffer)))
-       {
+            SCST_NO_SENSE(cmd->sense_buffer))) {
                TRACE(TRACE_SCSI|TRACE_MINOR, "CHECK_CONDITION, but no sense: "
                      "cmd->status=%x, cmd->msg_status=%x, "
                      "cmd->host_status=%x, cmd->driver_status=%x", cmd->status,
@@ -2072,7 +2039,8 @@ static int scst_check_auto_sense(struct scst_cmd *cmd)
        } else if (unlikely(cmd->host_status)) {
                if ((cmd->host_status == DID_REQUEUE) ||
                    (cmd->host_status == DID_IMM_RETRY) ||
-                   (cmd->host_status == DID_SOFT_ERROR)) {
+                   (cmd->host_status == DID_SOFT_ERROR) ||
+                   (cmd->host_status == DID_ABORT)) {
                        scst_set_busy(cmd);
                } else {
                        TRACE(TRACE_SCSI|TRACE_MINOR, "Host status %x "
@@ -2089,7 +2057,6 @@ static int scst_check_auto_sense(struct scst_cmd *cmd)
 static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres)
 {
        int res = 0, rc;
-       unsigned char type;
 
        TRACE_ENTRY();
 
@@ -2111,45 +2078,43 @@ static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres)
                        scst_set_cmd_error(cmd,
                                SCST_LOAD_SENSE(scst_sense_hardw_error));
                }
-       } else if (scst_check_sense(cmd)) {
+       } else if (unlikely(scst_check_sense(cmd))) {
                *pres = SCST_CMD_STATE_RES_CONT_SAME;
                res = 1;
                goto out;
        }
 
-       type = cmd->dev->handler->type;
-       if ((cmd->cdb[0] == MODE_SENSE || cmd->cdb[0] == MODE_SENSE_10) &&
-           cmd->tgt_dev->acg_dev->rd_only_flag &&
-           (type == TYPE_DISK || type == TYPE_WORM || type == TYPE_MOD ||
-            type == TYPE_TAPE))
-       {
-               int32_t length;
-               uint8_t *address;
-
-               length = scst_get_buf_first(cmd, &address);
-               if (length <= 0)
-                       goto out;
-               if (length > 2 && cmd->cdb[0] == MODE_SENSE)
-                       address[2] |= 0x80;   /* Write Protect*/
-               else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10)
-                       address[3] |= 0x80;   /* Write Protect*/
-               scst_put_buf(cmd, address);
-       }
+       if (likely(scsi_status_is_good(cmd->status))) {
+               unsigned char type = cmd->dev->handler->type;
+               if ((cmd->cdb[0] == MODE_SENSE || cmd->cdb[0] == MODE_SENSE_10) &&
+                   cmd->tgt_dev->acg_dev->rd_only_flag &&
+                   (type == TYPE_DISK || type == TYPE_WORM || type == TYPE_MOD ||
+                    type == TYPE_TAPE)) {
+                       int32_t length;
+                       uint8_t *address;
 
-       /* 
-        * Check and clear NormACA option for the device, if necessary,
-        * since we don't support ACA
-        */
-       if ((cmd->cdb[0] == INQUIRY) &&
-           !(cmd->cdb[1] & SCST_INQ_EVPD/* Std INQUIRY data (no EVPD) */) &&
-           (cmd->resp_data_len > SCST_INQ_BYTE3))
-       {
-               uint8_t *buffer;
-               int buflen;
+                       length = scst_get_buf_first(cmd, &address);
+                       if (length <= 0)
+                               goto out;
+                       if (length > 2 && cmd->cdb[0] == MODE_SENSE)
+                               address[2] |= 0x80;   /* Write Protect*/
+                       else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10)
+                               address[3] |= 0x80;   /* Write Protect*/
+                       scst_put_buf(cmd, address);
+               }
 
-               /* ToDo: all pages ?? */
-               buflen = scst_get_buf_first(cmd, &buffer);
-               if (buflen > 0) {
+               /* 
+                * Check and clear NormACA option for the device, if necessary,
+                * since we don't support ACA
+                */
+               if ((cmd->cdb[0] == INQUIRY) &&
+                   !(cmd->cdb[1] & SCST_INQ_EVPD/* Std INQUIRY data (no EVPD) */) &&
+                   (cmd->resp_data_len > SCST_INQ_BYTE3)) {
+                       uint8_t *buffer;
+                       int buflen;
+
+                       /* ToDo: all pages ?? */
+                       buflen = scst_get_buf_first(cmd, &buffer);
                        if (buflen > SCST_INQ_BYTE3) {
 #ifdef EXTRACHECKS
                                if (buffer[SCST_INQ_BYTE3] & SCST_INQ_NORMACA_BIT) {
@@ -2159,40 +2124,105 @@ static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres)
                                }
 #endif
                                buffer[SCST_INQ_BYTE3] &= ~SCST_INQ_NORMACA_BIT;
-                       } else
+                       } else {
+                               PRINT_ERROR("%s", "Unable to get INQUIRY "
+                                   "buffer");
                                scst_set_cmd_error(cmd,
                                   SCST_LOAD_SENSE(scst_sense_hardw_error));
-
-                       scst_put_buf(cmd, buffer);
+                       }
+                       if (buflen > 0)
+                               scst_put_buf(cmd, buffer);
                }
-       }
 
-       if (unlikely((cmd->cdb[0] == RESERVE) || (cmd->cdb[0] == RESERVE_10))) {
-               if ((cmd->status != 0) && !test_bit(SCST_TGT_DEV_RESERVED,
-                                               &cmd->tgt_dev->tgt_dev_flags)) {
-                       struct scst_tgt_dev *tgt_dev_tmp;
-                       TRACE(TRACE_SCSI, "Real RESERVE failed lun=%Ld, status=%x",
-                             (uint64_t)cmd->lun, cmd->status);
-                       TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer,
-                                    sizeof(cmd->sense_buffer));
-                       /* Clearing the reservation */
-                       list_for_each_entry(tgt_dev_tmp, &cmd->dev->dev_tgt_dev_list,
-                                           dev_tgt_dev_list_entry) {
-                               clear_bit(SCST_TGT_DEV_RESERVED, 
-                                       &tgt_dev_tmp->tgt_dev_flags);
+               if (unlikely((cmd->cdb[0] == MODE_SELECT) || 
+                   (cmd->cdb[0] == MODE_SELECT_10) ||
+                   (cmd->cdb[0] == LOG_SELECT))) {
+                       TRACE(TRACE_SCSI, "MODE/LOG SELECT succeeded (LUN %Ld)",
+                               (uint64_t)cmd->lun);
+                       cmd->state = SCST_CMD_STATE_MODE_SELECT_CHECKS;
+                       *pres = SCST_CMD_STATE_RES_CONT_SAME;
+                       res = 1;
+                       goto out;
+               }
+       } else {
+               if ((cmd->cdb[0] == RESERVE) || (cmd->cdb[0] == RESERVE_10)) {
+                       if (!test_bit(SCST_TGT_DEV_RESERVED,
+                                       &cmd->tgt_dev->tgt_dev_flags)) {
+                               struct scst_tgt_dev *tgt_dev_tmp;
+                               TRACE(TRACE_SCSI, "Real RESERVE failed lun=%Ld, status=%x",
+                                     (uint64_t)cmd->lun, cmd->status);
+                               TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer,
+                                            sizeof(cmd->sense_buffer));
+                               /* Clearing the reservation */
+                               list_for_each_entry(tgt_dev_tmp, &cmd->dev->dev_tgt_dev_list,
+                                                   dev_tgt_dev_list_entry) {
+                                       clear_bit(SCST_TGT_DEV_RESERVED, 
+                                               &tgt_dev_tmp->tgt_dev_flags);
+                               }
+                               cmd->dev->dev_reserved = 0;
                        }
-                       cmd->dev->dev_reserved = 0;
+               }
+
+               /* Check for MODE PARAMETERS CHANGED UA */
+               if ((cmd->dev->scsi_dev != NULL) &&
+                   (cmd->status == SAM_STAT_CHECK_CONDITION) && 
+                   SCST_SENSE_VALID(cmd->sense_buffer) &&
+                   scst_is_ua_sense(cmd->sense_buffer) &&
+                   (cmd->sense_buffer[12] == 0x2a) &&
+                   (cmd->sense_buffer[13] == 0x01)) {
+                       TRACE(TRACE_SCSI, "MODE PARAMETERS CHANGED UA (lun %Ld)",
+                               (uint64_t)cmd->lun);
+                       cmd->state = SCST_CMD_STATE_MODE_SELECT_CHECKS;
+                       *pres = SCST_CMD_STATE_RES_CONT_SAME;
+                       res = 1;
+                       goto out;
                }
        }
-       
-       if (unlikely((cmd->cdb[0] == MODE_SELECT) || 
-                    (cmd->cdb[0] == MODE_SELECT_10) ||
-                    (cmd->cdb[0] == LOG_SELECT)))
-       {
-               if (cmd->status == 0) {
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static int scst_pre_dev_done(struct scst_cmd *cmd)
+{
+       int res = SCST_CMD_STATE_RES_CONT_SAME, rc;
+
+       TRACE_ENTRY();
+
+       rc = scst_done_cmd_check(cmd, &res);
+       if (rc)
+               goto out;
+
+       cmd->state = SCST_CMD_STATE_DEV_DONE;
+
+out:
+       TRACE_EXIT_HRES(res);
+       return res;
+}
+
+static int scst_mode_select_checks(struct scst_cmd *cmd)
+{
+       int res = SCST_CMD_STATE_RES_CONT_SAME;
+       int atomic = scst_cmd_atomic(cmd);
+
+       TRACE_ENTRY();
+
+       if (likely(scsi_status_is_good(cmd->status))) {
+               if (unlikely((cmd->cdb[0] == MODE_SELECT) || 
+                   (cmd->cdb[0] == MODE_SELECT_10) ||
+                   (cmd->cdb[0] == LOG_SELECT))) {
+                       if (atomic && (cmd->dev->scsi_dev != NULL)) {
+                               TRACE_DBG("%s", "MODE/LOG SELECT: thread "
+                                       "context required");
+                               res = SCST_CMD_STATE_RES_NEED_THREAD;
+                               goto out;
+                       }
+
                        TRACE(TRACE_SCSI, "MODE/LOG SELECT succeeded, "
                                "setting the SELECT UA (lun=%Ld)", 
                                (uint64_t)cmd->lun);
+
                        spin_lock_bh(&scst_temp_UA_lock);
                        if (cmd->cdb[0] == LOG_SELECT) {
                                scst_set_sense(scst_temp_UA,
@@ -2203,27 +2233,67 @@ static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres)
                                        sizeof(scst_temp_UA),
                                        UNIT_ATTENTION, 0x2a, 0x01);
                        }
-                       scst_process_UA(cmd->dev, cmd, scst_temp_UA,
-                               sizeof(scst_temp_UA), 1);
+                       scst_dev_check_set_local_UA(cmd->dev, cmd, scst_temp_UA,
+                               sizeof(scst_temp_UA));
                        spin_unlock_bh(&scst_temp_UA_lock);
+
+                       if (cmd->dev->scsi_dev != NULL)
+                               scst_obtain_device_parameters(cmd->dev);
+               }
+       } else if ((cmd->status == SAM_STAT_CHECK_CONDITION) && 
+                   SCST_SENSE_VALID(cmd->sense_buffer) &&
+                   scst_is_ua_sense(cmd->sense_buffer) &&
+                   (cmd->sense_buffer[12] == 0x2a) &&
+                   (cmd->sense_buffer[13] == 0x01)) {
+               if (atomic) {
+                       TRACE_DBG("%s", "MODE PARAMETERS CHANGED UA: thread "
+                               "context required");
+                       res = SCST_CMD_STATE_RES_NEED_THREAD;
+                       goto out;
                }
-       }
+
+               TRACE(TRACE_SCSI, "MODE PARAMETERS CHANGED UA (lun %Ld): "
+                       "getting new parameters", (uint64_t)cmd->lun);
+
+               scst_obtain_device_parameters(cmd->dev);
+       } else
+               sBUG();
+
+       cmd->state = SCST_CMD_STATE_DEV_DONE;
 
 out:
-       TRACE_EXIT_RES(res);
+       TRACE_EXIT_HRES(res);
        return res;
 }
 
+static void scst_inc_check_expected_sn(struct scst_cmd *cmd)
+{
+       struct scst_cmd *c;
+
+       if (likely(cmd->sn_set))
+               scst_inc_expected_sn(cmd->tgt_dev, cmd->sn_slot);
+
+       c = scst_check_deferred_commands(cmd->tgt_dev);
+       if (c != NULL) {
+               unsigned long flags;
+               spin_lock_irqsave(&c->cmd_lists->cmd_list_lock, flags);
+               TRACE_SN("Adding cmd %p to active cmd list", c);
+               list_add_tail(&c->cmd_list_entry,
+                       &c->cmd_lists->active_cmd_list);
+               wake_up(&c->cmd_lists->cmd_list_waitQ);
+               spin_unlock_irqrestore(&c->cmd_lists->cmd_list_lock, flags);
+       }
+}
+
 static int scst_dev_done(struct scst_cmd *cmd)
 {
-       int res = SCST_CMD_STATE_RES_CONT_SAME, rc;
+       int res = SCST_CMD_STATE_RES_CONT_SAME;
        int state;
        int atomic = scst_cmd_atomic(cmd);
 
        TRACE_ENTRY();
 
-       if (atomic && !cmd->dev->handler->dev_done_atomic) 
-       {
+       if (atomic && !cmd->dev->handler->dev_done_atomic) {
                TRACE_DBG("Dev handler %s dev_done() can not be "
                      "called in atomic context, rescheduling to the thread",
                      cmd->dev->handler->name);
@@ -2231,18 +2301,7 @@ static int scst_dev_done(struct scst_cmd *cmd)
                goto out;
        }
 
-       rc = scst_done_cmd_check(cmd, &res);
-
-       if (cmd->needs_unblocking)
-               scst_unblock_dev_cmd(cmd);
-
-       if (unlikely(cmd->dec_on_dev_needed))
-               scst_dec_on_dev_cmd(cmd);
-
-       if (rc)
-               goto out;
-
-       state = SCST_CMD_STATE_XMIT_RESP;
+       state = SCST_CMD_STATE_PRE_XMIT_RESP;
        if (likely(!scst_is_cmd_local(cmd)) && 
            likely(cmd->dev->handler->dev_done != NULL))
        {
@@ -2257,13 +2316,17 @@ static int scst_dev_done(struct scst_cmd *cmd)
        }
 
        switch (state) {
-       case SCST_CMD_STATE_XMIT_RESP:
+       case SCST_CMD_STATE_PRE_XMIT_RESP:
        case SCST_CMD_STATE_DEV_PARSE:
+       case SCST_CMD_STATE_PRE_PARSE:
        case SCST_CMD_STATE_PREPARE_SPACE:
        case SCST_CMD_STATE_RDY_TO_XFER:
-       case SCST_CMD_STATE_PRE_EXEC:
+       case SCST_CMD_STATE_TGT_PRE_EXEC:
        case SCST_CMD_STATE_SEND_TO_MIDLEV:
+       case SCST_CMD_STATE_PRE_DEV_DONE:
+       case SCST_CMD_STATE_MODE_SELECT_CHECKS:
        case SCST_CMD_STATE_DEV_DONE:
+       case SCST_CMD_STATE_XMIT_RESP:
        case SCST_CMD_STATE_FINISHED:
                cmd->state = state;
                res = SCST_CMD_STATE_RES_CONT_SAME;
@@ -2288,55 +2351,34 @@ static int scst_dev_done(struct scst_cmd *cmd)
                }
                scst_set_cmd_error(cmd,
                           SCST_LOAD_SENSE(scst_sense_hardw_error));
-               cmd->state = SCST_CMD_STATE_XMIT_RESP;
+               cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
                res = SCST_CMD_STATE_RES_CONT_SAME;
                break;
        }
 
+       if (cmd->needs_unblocking)
+               scst_unblock_dev_cmd(cmd);
+
+       if (likely(cmd->dec_on_dev_needed))
+               scst_dec_on_dev_cmd(cmd);
+
+       if (cmd->inc_expected_sn_on_done && cmd->sent_to_midlev)
+               scst_inc_check_expected_sn(cmd);
+
 out:
        TRACE_EXIT_HRES(res);
        return res;
 }
 
-static int scst_xmit_response(struct scst_cmd *cmd)
+static int scst_pre_xmit_response(struct scst_cmd *cmd)
 {
-       int res, rc;
-       int atomic = scst_cmd_atomic(cmd);
+       int res;
 
        TRACE_ENTRY();
 
-       /*
-        * Check here also in order to avoid unnecessary delays of other
-        * commands.
-        */
        if (cmd->tgt_dev != NULL) {
-               if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE)) {
-                       struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
-
-                       spin_lock_irq(&tgt_dev->sn_lock);
-                       tgt_dev->hq_cmd_count--;
-                       spin_unlock_irq(&tgt_dev->sn_lock);
-
-                       EXTRACHECKS_BUG_ON(tgt_dev->hq_cmd_count < 0);
-
-                       /*
-                        * There is no problem in checking hq_cmd_count in the
-                        * non-locked state. In the worst case we will only have
-                        * unneeded run of the deferred commands.
-                        */
-                       if (tgt_dev->hq_cmd_count == 0) {
-                               struct scst_cmd *c =
-                                       scst_check_deferred_commands(tgt_dev);
-                               if (c != NULL) {
-                                       spin_lock_irq(&c->cmd_lists->cmd_list_lock);
-                                       TRACE_SN("Adding cmd %p to active cmd list", c);
-                                       list_add_tail(&c->cmd_list_entry,
-                                               &c->cmd_lists->active_cmd_list);
-                                       wake_up(&c->cmd_lists->cmd_list_waitQ);
-                                       spin_unlock_irq(&c->cmd_lists->cmd_list_lock);
-                               }
-                       }
-               }
+               if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
+                       scst_on_hq_cmd_response(cmd);
 
                if (unlikely(!cmd->sent_to_midlev)) {
                        TRACE_SN("cmd %p was not sent to mid-lev (sn %ld, set %d)",
@@ -2346,13 +2388,6 @@ static int scst_xmit_response(struct scst_cmd *cmd)
                }
        }
 
-       if (atomic && !cmd->tgtt->xmit_response_atomic) {
-               TRACE_DBG("%s", "xmit_response() can not be "
-                     "called in atomic context, rescheduling to the thread");
-               res = SCST_CMD_STATE_RES_NEED_THREAD;
-               goto out;
-       }
-
        /*
         * If we don't remove cmd from the search list here, before
         * submitting it for transmittion, we will have a race, when for
@@ -2364,23 +2399,8 @@ static int scst_xmit_response(struct scst_cmd *cmd)
        list_del(&cmd->search_cmd_list_entry);
        spin_unlock_irq(&cmd->sess->sess_list_lock);
 
-       set_bit(SCST_CMD_XMITTING, &cmd->cmd_flags);
-       smp_mb__after_set_bit();
-
-       if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
-               if (test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags)) {
-                       if (cmd->completed) {
-                               /* It's completed and it's OK to return its result */
-                               clear_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
-                               clear_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
-                       } else {
-                               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);
-                       }
-               }
-       }
+       if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
+               scst_xmit_process_aborted_cmd(cmd);
 
        if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
                TRACE_MGMT_DBG("Flag NO_RESP set for cmd %p (tag %llu), skipping",
@@ -2390,6 +2410,28 @@ static int scst_xmit_response(struct scst_cmd *cmd)
                goto out;
        }
 
+       cmd->state = SCST_CMD_STATE_XMIT_RESP;
+       res = SCST_CMD_STATE_RES_CONT_SAME;
+
+out:
+       TRACE_EXIT_HRES(res);
+       return res;
+}
+
+static int scst_xmit_response(struct scst_cmd *cmd)
+{
+       int res, rc;
+       int atomic = scst_cmd_atomic(cmd);
+
+       TRACE_ENTRY();
+
+       if (atomic && !cmd->tgtt->xmit_response_atomic) {
+               TRACE_DBG("%s", "xmit_response() can not be "
+                     "called in atomic context, rescheduling to the thread");
+               res = SCST_CMD_STATE_RES_NEED_THREAD;
+               goto out;
+       }
+
 #ifdef DEBUG_TM
        if (cmd->tm_dbg_delayed && !test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
                if (atomic && !cmd->tgtt->xmit_response_atomic) {
@@ -2438,25 +2480,21 @@ static int scst_xmit_response(struct scst_cmd *cmd)
                        goto out;
 
                /* Restore the previous state */
-               cmd->state = SCST_CMD_STATE_XMIT_RESP;
+               cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
 
                switch (rc) {
                case SCST_TGT_RES_QUEUE_FULL:
-               {
                        if (scst_queue_retry_cmd(cmd, finished_cmds) == 0)
                                break;
                        else
                                continue;
-               }
 
                case SCST_TGT_RES_NEED_THREAD_CTX:
-               {
                        TRACE_DBG("Target driver %s xmit_response() "
                              "requested thread context, rescheduling",
                              cmd->tgtt->name);
                        res = SCST_CMD_STATE_RES_NEED_THREAD;
                        break;
-               }
 
                default:
                        goto out_error;
@@ -2510,6 +2548,15 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
                        atomic_read(&scst_cmd_count));
        }
 
+       if (unlikely(cmd->delivery_status != SCST_CMD_DELIVERY_SUCCESS)) {
+               if ((cmd->tgt_dev != NULL) &&
+                   scst_is_ua_sense(cmd->sense_buffer)) {
+                       /* This UA delivery failed, so requeue it */
+                       scst_check_set_UA(cmd->tgt_dev, cmd->sense_buffer,
+                                       sizeof(cmd->sense_buffer), 1);
+               }
+       }
+
        scst_cmd_put(cmd);
 
        res = SCST_CMD_STATE_RES_CONT_NEXT;
@@ -2536,9 +2583,19 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd)
 
        scst_check_debug_sn(cmd);
 
+       if (cmd->dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER)
+               cmd->queue_type = SCST_CMD_QUEUE_ORDERED;
+
        switch(cmd->queue_type) {
        case SCST_CMD_QUEUE_SIMPLE:
        case SCST_CMD_QUEUE_UNTAGGED:
+#if 1 /* temporary, ToDo */
+               if (scst_cmd_is_expected_set(cmd)) {
+                       if (cmd->expected_data_direction == SCST_DATA_READ)
+                               goto ordered;
+               } else
+                       goto ordered;
+#endif
                if (likely(tgt_dev->num_free_sn_slots >= 0)) {
                        if (atomic_inc_return(tgt_dev->cur_sn_slot) == 1) {
                                tgt_dev->curr_sn++;
@@ -2592,10 +2649,7 @@ ordered:
                goto out;
 
        default:
-               PRINT_ERROR("Unsupported queue type %d, treating it as "
-                       "ORDERED", cmd->queue_type);
-               cmd->queue_type = SCST_CMD_QUEUE_ORDERED;
-               goto ordered;
+               sBUG();
        }
 
        TRACE_SN("cmd(%p)->sn: %ld (tgt_dev %p, *cur_sn_slot %d, "
@@ -2682,10 +2736,10 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
        res = scst_translate_lun(cmd);
        if (likely(res == 0)) {
                int cnt;
-               cmd->state = SCST_CMD_STATE_DEV_PARSE;
+               cmd->state = SCST_CMD_STATE_PRE_PARSE;
                cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count);
                if (unlikely(cnt > SCST_MAX_TGT_DEV_COMMANDS)) {
-                       TRACE(TRACE_RETRY, "Too many pending commands (%d) in "
+                       TRACE(TRACE_MGMT_MINOR, "Too many pending commands (%d) in "
                                "session, returning BUSY to initiator \"%s\"",
                                cnt, (cmd->sess->initiator_name[0] == '\0') ?
                                  "Anonymous" : cmd->sess->initiator_name);
@@ -2693,7 +2747,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
                }
                cnt = atomic_inc_return(&cmd->dev->dev_cmd_count);
                if (unlikely(cnt > SCST_MAX_DEV_COMMANDS)) {
-                       TRACE(TRACE_RETRY, "Too many pending device commands "
+                       TRACE(TRACE_MGMT_MINOR, "Too many pending device commands "
                                "(%d), returning BUSY to initiator \"%s\"",
                                cnt, (cmd->sess->initiator_name[0] == '\0') ?
                                  "Anonymous" : cmd->sess->initiator_name);
@@ -2705,7 +2759,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
                TRACE_DBG("Finishing cmd %p", cmd);
                scst_set_cmd_error(cmd,
                           SCST_LOAD_SENSE(scst_sense_lun_not_supported));
-               cmd->state = SCST_CMD_STATE_XMIT_RESP;
+               cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
        } else
                goto out;
 
@@ -2715,7 +2769,7 @@ out:
 
 out_busy:
        scst_set_busy(cmd);
-       cmd->state = SCST_CMD_STATE_XMIT_RESP;
+       cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
        goto out;
 }
 
@@ -2747,7 +2801,7 @@ restart:
                } else {
                        TRACE_MGMT_DBG("Aborting not inited cmd %p (tag %llu)",
                                cmd, cmd->tag);
-                       cmd->state = SCST_CMD_STATE_XMIT_RESP;
+                       cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
                }
 
                /*
@@ -2804,6 +2858,8 @@ int scst_init_cmd_thread(void *arg)
 
        current->flags |= PF_NOFREEZE;
 
+       set_user_nice(current, -20);
+
        spin_lock_irq(&scst_init_lock);
        while(!kthread_should_stop()) {
                wait_queue_t wait;
@@ -2850,12 +2906,13 @@ void scst_process_active_cmd(struct scst_cmd *cmd, int context)
 
        do {
                switch (cmd->state) {
+               case SCST_CMD_STATE_PRE_PARSE:
+                       res = scst_pre_parse(cmd);
+                       break;
+
                case SCST_CMD_STATE_DEV_PARSE:
                        res = scst_parse_cmd(cmd);
-                       if ((res != SCST_CMD_STATE_RES_CONT_SAME) ||
-                           (cmd->state != SCST_CMD_STATE_PREPARE_SPACE))
-                               break;
-                       /* else go through */
+                       break;
 
                case SCST_CMD_STATE_PREPARE_SPACE:
                        res = scst_prepare_space(cmd);
@@ -2865,12 +2922,9 @@ void scst_process_active_cmd(struct scst_cmd *cmd, int context)
                        res = scst_rdy_to_xfer(cmd);
                        break;
 
-               case SCST_CMD_STATE_PRE_EXEC:
+               case SCST_CMD_STATE_TGT_PRE_EXEC:
                        res = scst_tgt_pre_exec(cmd);
-                       if ((res != SCST_CMD_STATE_RES_CONT_SAME) ||
-                           (cmd->state != SCST_CMD_STATE_SEND_TO_MIDLEV))
-                               break;
-                       /* else go through */
+                       break;
 
                case SCST_CMD_STATE_SEND_TO_MIDLEV:
                        if (tm_dbg_check_cmd(cmd) != 0) {
@@ -2884,12 +2938,20 @@ void scst_process_active_cmd(struct scst_cmd *cmd, int context)
                        /* !! At this point cmd, sess & tgt_dev can be already freed !! */
                        break;
 
+               case SCST_CMD_STATE_PRE_DEV_DONE:
+                       res = scst_pre_dev_done(cmd);
+                       break;
+
+               case SCST_CMD_STATE_MODE_SELECT_CHECKS:
+                       res = scst_mode_select_checks(cmd);
+                       break;
+
                case SCST_CMD_STATE_DEV_DONE:
                        res = scst_dev_done(cmd);
-                       if ((res != SCST_CMD_STATE_RES_CONT_SAME) ||
-                           (cmd->state != SCST_CMD_STATE_XMIT_RESP))
-                               break;
-                       /* else go through */
+                       break;
+
+               case SCST_CMD_STATE_PRE_XMIT_RESP:
+                       res = scst_pre_xmit_response(cmd);
                        break;
 
                case SCST_CMD_STATE_XMIT_RESP:
@@ -2914,12 +2976,16 @@ void scst_process_active_cmd(struct scst_cmd *cmd, int context)
        } else if (res == SCST_CMD_STATE_RES_NEED_THREAD) {
                spin_lock_irq(&cmd->cmd_lists->cmd_list_lock);
                switch (cmd->state) {
+               case SCST_CMD_STATE_PRE_PARSE:
                case SCST_CMD_STATE_DEV_PARSE:
                case SCST_CMD_STATE_PREPARE_SPACE:
                case SCST_CMD_STATE_RDY_TO_XFER:
-               case SCST_CMD_STATE_PRE_EXEC:
+               case SCST_CMD_STATE_TGT_PRE_EXEC:
                case SCST_CMD_STATE_SEND_TO_MIDLEV:
+               case SCST_CMD_STATE_PRE_DEV_DONE:
+               case SCST_CMD_STATE_MODE_SELECT_CHECKS:
                case SCST_CMD_STATE_DEV_DONE:
+               case SCST_CMD_STATE_PRE_XMIT_RESP:
                case SCST_CMD_STATE_XMIT_RESP:
                case SCST_CMD_STATE_FINISHED:
                        TRACE_DBG("Adding cmd %p to head of active cmd list", cmd);
@@ -3169,8 +3235,10 @@ static inline int scst_is_strict_mgmt_fn(int mgmt_fn)
 {
        switch(mgmt_fn) {
                case SCST_ABORT_TASK:
+#if 0
                case SCST_ABORT_TASK_SET:
                case SCST_CLEAR_TASK_SET:
+#endif
                        return 1;
                default:
                        return 0;
@@ -3186,11 +3254,15 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
 {
        TRACE_ENTRY();
 
-       TRACE(TRACE_MGMT, "Aborting cmd %p (tag %llu)", cmd, cmd->tag);
+       TRACE(((mcmd != NULL) && (mcmd->fn == SCST_ABORT_TASK)) ? TRACE_MGMT_MINOR : TRACE_MGMT,
+               "Aborting cmd %p (tag %llu)", cmd, cmd->tag);
 
        if (other_ini) {
                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);
        smp_mb__after_set_bit();
@@ -3218,9 +3290,9 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
                 * we must wait here to be sure that we won't receive
                 * double commands with the same tag.
                 */
-               TRACE(TRACE_MGMT, "cmd %p (tag %llu) being executed/"
-                       "xmitted (state %d), deferring ABORT...", cmd,
-                       cmd->tag, cmd->state);
+               TRACE((mcmd->fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
+                       "cmd %p (tag %llu) being executed/xmitted (state %d), "
+                       "deferring ABORT...", cmd, cmd->tag, cmd->state);
 #ifdef EXTRACHECKS
                if (cmd->mgmt_cmnd) {
                        printk(KERN_ALERT "cmd %p (tag %llu, state %d) "
@@ -3327,7 +3399,6 @@ static void scst_unblock_aborted_cmds(int scst_mutex_held)
        return;
 }
 
-/* Returns 0 if the command processing should be continued, <0 otherwise */
 static void __scst_abort_task_set(struct scst_mgmt_cmd *mcmd,
        struct scst_tgt_dev *tgt_dev, int other_ini, int scst_mutex_held)
 {
@@ -3386,6 +3457,104 @@ static int scst_abort_task_set(struct scst_mgmt_cmd *mcmd)
        return res;
 }
 
+static int scst_is_cmd_belongs_to_dev(struct scst_cmd *cmd,
+       struct scst_device *dev)
+{
+       struct scst_tgt_dev *tgt_dev = NULL;
+       struct list_head *sess_tgt_dev_list_head;
+       int res = 0;
+
+       TRACE_ENTRY();
+
+       TRACE_DBG("Finding match for dev %p and cmd %p (lun %Ld)", dev, cmd,
+             (uint64_t)cmd->lun);
+
+       sess_tgt_dev_list_head =
+               &cmd->sess->sess_tgt_dev_list_hash[HASH_VAL(cmd->lun)];
+       list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
+                       sess_tgt_dev_list_entry) {
+               if (tgt_dev->lun == cmd->lun) {
+                       TRACE_DBG("dev %p found", tgt_dev->dev);
+                       res = (tgt_dev->dev == dev);
+                       goto out;
+               }
+       }
+
+out:
+       TRACE_EXIT_HRES(res);
+       return res;
+}
+
+/* Returns 0 if the command processing should be continued, <0 otherwise */
+static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd)
+{
+       int res;
+       struct scst_device *dev = mcmd->mcmd_tgt_dev->dev;
+       struct scst_tgt_dev *tgt_dev;
+       LIST_HEAD(UA_tgt_devs);
+
+       TRACE_ENTRY();
+
+       TRACE(TRACE_MGMT, "Clearing task set (lun=%Ld, mcmd=%p)",
+               (uint64_t)mcmd->lun, mcmd);
+
+       mcmd->needs_unblocking = 1;
+
+       spin_lock_bh(&dev->dev_lock);
+       __scst_block_dev(dev);
+       spin_unlock_bh(&dev->dev_lock);
+
+       __scst_abort_task_set(mcmd, mcmd->mcmd_tgt_dev, 0, 0);
+
+       list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, 
+               dev_tgt_dev_list_entry) 
+       {
+               struct scst_session *sess = tgt_dev->sess;
+               struct scst_cmd *cmd;
+               int aborted = 0;
+
+               if (tgt_dev == mcmd->mcmd_tgt_dev)
+                       continue;
+
+               spin_lock_irq(&sess->sess_list_lock);
+
+               TRACE_DBG("Searching in search cmd list (sess=%p)", sess);
+               list_for_each_entry(cmd, &sess->search_cmd_list, 
+                               search_cmd_list_entry) {
+                       if ((cmd->dev == dev) ||
+                           ((cmd->dev == NULL) && 
+                            scst_is_cmd_belongs_to_dev(cmd, dev))) {
+                               scst_abort_cmd(cmd, mcmd, 1, 0);
+                               aborted = 1;
+                       }
+               }
+               spin_unlock_irq(&sess->sess_list_lock);
+
+               if (aborted)
+                       list_add_tail(&tgt_dev->extra_tgt_dev_list_entry,
+                                       &UA_tgt_devs);
+       }
+
+       scst_unblock_aborted_cmds(0);
+
+       if (!dev->tas) {
+               list_for_each_entry(tgt_dev, &UA_tgt_devs, extra_tgt_dev_list_entry) {
+                       spin_lock_bh(&scst_temp_UA_lock);
+                       scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
+                               SCST_LOAD_SENSE(scst_sense_cleared_by_another_ini_UA));
+                       scst_check_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA), 0);
+                       spin_unlock_bh(&scst_temp_UA_lock);
+               }
+       }
+
+       scst_call_dev_task_mgmt_fn(mcmd, mcmd->mcmd_tgt_dev, 0);
+
+       res = scst_set_mcmd_next_state(mcmd);
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
 static int scst_check_delay_mgmt_cmd(struct scst_mgmt_cmd *mcmd)
 {
        if (test_bit(SCST_FLAG_TM_ACTIVE, &scst_flags) && !mcmd->active) {
@@ -3426,8 +3595,8 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
                spin_lock_irq(&sess->sess_list_lock);
                cmd = __scst_find_cmd_by_tag(sess, mcmd->tag);
                if (cmd == NULL) {
-                       TRACE(TRACE_MGMT, "ABORT TASK failed: command for "
-                               "tag %llu not found", mcmd->tag);
+                       TRACE(TRACE_MGMT_MINOR, "ABORT TASK failed: command "
+                               "for tag %llu not found", mcmd->tag);
                        mcmd->status = SCST_MGMT_STATUS_TASK_NOT_EXIST;
                        mcmd->state = SCST_MGMT_CMD_STATE_DONE;
                        spin_unlock_irq(&sess->sess_list_lock);
@@ -3435,7 +3604,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
                }
                scst_cmd_get(cmd);
                spin_unlock_irq(&sess->sess_list_lock);
-               TRACE(TRACE_MGMT, "Cmd %p for tag %llu (sn %ld, set %d, "
+               TRACE(TRACE_MGMT_MINOR, "Cmd %p for tag %llu (sn %ld, set %d, "
                        "queue_type %x) found, aborting it", cmd, mcmd->tag,
                        cmd->sn, cmd->sn_set, cmd->queue_type);
                mcmd->cmd_to_abort = cmd;
@@ -3504,6 +3673,18 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
        list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
                int found = 0;
 
+               /* Skip local SCSI devices */
+               if (dev->handler == &scst_null_devtype) {
+                        /*
+                         * Generally we shouldn't reset not exported devices,
+                         * but what if a backstorage SCSI disk hung? Let's
+                         * reset it too.
+                         */
+                       if ((dev->scsi_dev != NULL) &&
+                           (dev->scsi_dev->type != TYPE_DISK))
+                               continue;
+               }
+
                spin_lock_bh(&dev->dev_lock);
                __scst_block_dev(dev);
                scst_process_reset(dev, mcmd->sess, NULL, mcmd);
@@ -3528,16 +3709,15 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
                if (dev->scsi_dev == NULL)
                        continue;
 
-               list_for_each_entry(d, &host_devs, reset_dev_list_entry) {
+               list_for_each_entry(d, &host_devs, tm_dev_list_entry) {
                        if (dev->scsi_dev->host->host_no ==
-                                   d->scsi_dev->host->host_no) 
-                       {
+                                   d->scsi_dev->host->host_no) {
                                found = 1;
                                break;
                        }
                }
                if (!found)
-                       list_add_tail(&dev->reset_dev_list_entry, &host_devs);
+                       list_add_tail(&dev->tm_dev_list_entry, &host_devs);
        }
 
        /*
@@ -3545,7 +3725,7 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
         * on/after scsi_reset_provider() completion callbacks will be called.
         */
 
-       list_for_each_entry(dev, &host_devs, reset_dev_list_entry) {
+       list_for_each_entry(dev, &host_devs, tm_dev_list_entry) {
                /* dev->scsi_dev must be non-NULL here */
                TRACE(TRACE_MGMT, "Resetting host %d bus ",
                      dev->scsi_dev->host->host_no);
@@ -3553,11 +3733,13 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
                TRACE(TRACE_MGMT, "Result of host %d bus reset: %s",
                      dev->scsi_dev->host->host_no,
                      (rc == SUCCESS) ? "SUCCESS" : "FAILED");
+#if 0 /* scsi_reset_provider() returns very weird status, so let's always succeed */
                if ((rc != SUCCESS) &&
                    (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) {
                        /* SCSI_TRY_RESET_BUS is also done by scsi_reset_provider() */
                        mcmd->status = SCST_MGMT_STATUS_FAILED;
                }
+#endif
        }
 
        list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
@@ -3600,8 +3782,10 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
                TRACE(TRACE_MGMT, "Resetting host %d bus ",
                      dev->scsi_dev->host->host_no);
                rc = scsi_reset_provider(dev->scsi_dev, SCSI_TRY_RESET_DEVICE);
+#if 0 /* scsi_reset_provider() returns very weird status, so let's always succeed */
                if ((rc != SUCCESS) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS))
                        mcmd->status = SCST_MGMT_STATUS_FAILED;
+#endif
                dev->scsi_dev->was_reset = 0;
        }
 
@@ -3647,9 +3831,9 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
                        __scst_block_dev(dev);
                        spin_unlock_bh(&dev->dev_lock);
        
-                       __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1);
+                       __scst_abort_task_set(mcmd, tgt_dev, 0, 1);
                        if (nexus_loss)
-                               scst_reset_tgt_dev(tgt_dev, 1);
+                               scst_nexus_loss(tgt_dev);
        
                        rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
                        if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS))
@@ -3702,10 +3886,11 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
                        list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
                                        sess_tgt_dev_list_entry) {
                                int rc;
-       
-                               __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1);
+
+                               __scst_abort_task_set(mcmd, tgt_dev, 0, 1);
+
                                if (nexus_loss)
-                                       scst_reset_tgt_dev(tgt_dev, 1);
+                                       scst_nexus_loss(tgt_dev);
        
                                rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
                                if ((rc < 0) &&
@@ -3734,10 +3919,16 @@ static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd *mcmd)
 
        switch (mcmd->fn) {
        case SCST_ABORT_TASK_SET:
-       case SCST_CLEAR_TASK_SET:
                res = scst_abort_task_set(mcmd);
                break;
 
+       case SCST_CLEAR_TASK_SET:
+               if (mcmd->mcmd_tgt_dev->dev->tst == SCST_CONTR_MODE_SEP_TASK_SETS)
+                       res = scst_abort_task_set(mcmd);
+               else
+                       res = scst_clear_task_set(mcmd);
+               break;
+
        case SCST_LUN_RESET:
                res = scst_lun_reset(mcmd);
                break;
@@ -3924,6 +4115,8 @@ int scst_mgmt_cmd_thread(void *arg)
 
        current->flags |= PF_NOFREEZE;
 
+       set_user_nice(current, -20);
+
        spin_lock_irq(&scst_mcmd_lock);
        while(!kthread_should_stop()) {
                wait_queue_t wait;
@@ -4114,7 +4307,8 @@ int scst_rx_mgmt_fn(struct scst_session *sess,
        mcmd->cmd_sn_set = params->cmd_sn_set;
        mcmd->cmd_sn = params->cmd_sn;
 
-       TRACE(TRACE_MGMT, "sess=%p, fn %x, tag_set %d, tag %Ld, lun_set %d, "
+       TRACE((params->fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
+               "sess=%p, fn %x, tag_set %d, tag %Ld, lun_set %d, "
                "lun=%Ld, cmd_sn_set %d, cmd_sn %x", sess, params->fn,
                params->tag_set, params->tag, params->lun_set,
                (uint64_t)mcmd->lun, params->cmd_sn_set, params->cmd_sn);
@@ -4427,6 +4621,8 @@ int scst_mgmt_thread(void *arg)
 
        current->flags |= PF_NOFREEZE;
 
+       set_user_nice(current, -20);
+
        spin_lock_irq(&scst_mgmt_lock);
        while(!kthread_should_stop()) {
                wait_queue_t wait;
index d3c5f7f..53b231d 100644 (file)
@@ -32,6 +32,7 @@
 #include "common.h"
 
 static void exec_inquiry(struct vdisk_cmd *vcmd);
+static void exec_request_sense(struct vdisk_cmd *vcmd);
 static void exec_mode_sense(struct vdisk_cmd *vcmd);
 static void exec_mode_select(struct vdisk_cmd *vcmd);
 static void exec_read_capacity(struct vdisk_cmd *vcmd);
@@ -445,6 +446,9 @@ static int do_exec(struct vdisk_cmd *vcmd)
        case INQUIRY:
                exec_inquiry(vcmd);
                break;
+       case REQUEST_SENSE:
+               exec_request_sense(vcmd);
+               break;
        case READ_CAPACITY:
                exec_read_capacity(vcmd);
                break;
@@ -533,6 +537,11 @@ static int do_on_free_cmd(struct vdisk_cmd *vcmd)
 
        TRACE_ENTRY();
 
+       TRACE_DBG("On free cmd (cmd %d, resp_data_len %d, aborted %d, "
+               "status %d, delivery_status %d)", cmd->cmd_h,
+               cmd->on_free_cmd.resp_data_len, cmd->on_free_cmd.aborted,
+               cmd->on_free_cmd.status, cmd->on_free_cmd.delivery_status);
+
        TRACE_MEM("On free cmd (cmd %d, buf %Lx, buffer_cached %d)", cmd->cmd_h,
                cmd->on_free_cmd.pbuf, cmd->on_free_cmd.buffer_cached);
 
@@ -557,8 +566,9 @@ static int do_tm(struct vdisk_cmd *vcmd)
 
        TRACE_ENTRY();
 
-       TRACE(TRACE_MGMT, "TM fn %d (sess_h %Lx, cmd_h_to_abort %d)",
-               cmd->tm_cmd.fn, cmd->tm_cmd.sess_h, cmd->tm_cmd.cmd_h_to_abort);
+       TRACE((cmd->tm_cmd.fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
+               "TM fn %d (sess_h %Lx, cmd_h_to_abort %d)", cmd->tm_cmd.fn,
+               cmd->tm_cmd.sess_h, cmd->tm_cmd.cmd_h_to_abort);
 
        memset(reply, 0, sizeof(*reply));
        reply->cmd_h = cmd->cmd_h;
@@ -1026,6 +1036,31 @@ out:
        return;
 }
 
+static void exec_request_sense(struct vdisk_cmd *vcmd)
+{
+       struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
+       struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
+       int length = cmd->bufflen;
+       uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
+
+       TRACE_ENTRY();
+
+       if (length < SCST_STANDARD_SENSE_LEN) {
+               PRINT_ERROR("too small requested buffer for REQUEST SENSE "
+                       "(len %d)", length);
+               set_cmd_error(vcmd,
+                   SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
+               goto out;
+       }
+
+       set_sense(address, length, SCST_LOAD_SENSE(scst_sense_no_sense));
+       reply->resp_data_len = length;
+
+out:
+       TRACE_EXIT();
+       return;
+}
+
 /* 
  * <<Following mode pages info copied from ST318451LW with some corrections>>
  *
index 8bdd692..15d1362 100644 (file)
@@ -45,9 +45,9 @@
 struct vdisk_tgt_dev {
        uint64_t sess_h;
        /*
-        * last_write_cmd_queue_type accessed without protection since we are
-        * guaranteed that only commands of the same type per tgt_dev can be
-        * processed simultaneously
+        * Used without protection since we are guaranteed by SCST core
+        * that only commands with the same ORDERED type per tgt_dev can
+        * be processed simultaneously.
         */
        int last_write_cmd_queue_type;
 };
index 3121010..ee9929b 100644 (file)
@@ -47,11 +47,12 @@ extern pid_t gettid(void);
 #define TRACE_OUT_OF_MEM     0x00000100
 #define TRACE_MINOR          0x00000200 /* less important events */
 #define TRACE_MGMT           0x00000400
-#define TRACE_MGMT_DEBUG     0x00000800
-#define TRACE_SCSI           0x00001000
-#define TRACE_SPECIAL        0x00002000 /* filtering debug, etc */
-#define TRACE_TIME           0x00004000
-#define TRACE_ORDER          0x00008000
+#define TRACE_MGMT_MINOR     0x00000800
+#define TRACE_MGMT_DEBUG     0x00001000
+#define TRACE_SCSI           0x00002000
+#define TRACE_SPECIAL        0x00004000 /* filtering debug, etc */
+#define TRACE_TIME           0x00008000
+#define TRACE_ORDER          0x00010000
 #define TRACE_ALL            0xffffffff
 
 #define PRINT(format, args...)  fprintf(stdout, format "\n", ## args);
@@ -91,7 +92,7 @@ do {                                                          \
 do {                                                           \
   if (trace_flag & TRACE_BUFF)                                 \
   {                                                            \
-    debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    debug_print_prefix(trace_flag, NULL, __FUNCTION__,  \
                        __LINE__);                              \
     PRINT("%s:", message);                                     \
     debug_print_buffer(buff, len);                             \
@@ -102,18 +103,25 @@ do {                                                              \
 do {                                                           \
   if (trace_flag & (flag))                                     \
   {                                                            \
-    debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                        __LINE__);                              \
     PRINT("%s:", message);                                     \
     debug_print_buffer(buff, len);                             \
   }                                                            \
 } while(0)
 
+#define PRINT_BUFFER(message, buff, len)                       \
+do {                                                           \
+    PRINT("%s:", message);                                     \
+    debug_print_buffer(buff, len);                             \
+} while(0)
+
 #else  /* DEBUG || TRACING */
 
 #define TRACE(trace, args...) {}
 #define TRACE_BUFFER(message, buff, len) {}
 #define TRACE_BUFF_FLAG(flag, message, buff, len) {}
+#define PRINT_BUFFER(message, buff, len) {}
 
 static inline int debug_init(void) { return 0; }
 static inline void debug_done(void) {}
@@ -128,7 +136,7 @@ static inline void debug_done(void) {}
 do {                                                           \
   if (trace_flag & TRACE_MEMORY)                               \
   {                                                            \
-    debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                        __LINE__);                              \
     PRINT(format, args);                                       \
   }                                                            \
@@ -138,7 +146,7 @@ do {                                                                \
 do {                                                           \
   if (trace_flag & TRACE_DEBUG)                                        \
   {                                                            \
-    debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                        __LINE__);                              \
     PRINT(format, args);                                       \
   }                                                            \
@@ -148,7 +156,7 @@ do {                                                                \
 do {                                                           \
   if (trace_flag & TRACE_MGMT_DEBUG)                           \
   {                                                            \
-    debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,  \
+    debug_print_prefix(trace_flag, NULL, __FUNCTION__,          \
                        __LINE__);                              \
     PRINT(format, args);                                       \
   }                                                            \
@@ -156,12 +164,16 @@ do {                                                              \
 
 #define PRINT_ERROR(format, args...)                           \
 do {                                                           \
-  TRACE(trace_flag, "***ERROR*** " format, args);              \
+  debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,    \
+                       __LINE__);                              \
+  PRINT("***ERROR*** " format, args);                          \
 } while(0)
 
 #define PRINT_INFO(format, args...)                            \
 do {                                                           \
-  TRACE(trace_flag, format, args);                             \
+  debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__,    \
+                       __LINE__);                              \
+  PRINT(format, args);                                         \
 } while(0)
 
 #define TRACE_ENTRY()                                          \
index e3448ce..facbc67 100644 (file)
@@ -45,15 +45,15 @@ char *app_name;
        ~TRACE_SCSI & ~TRACE_SCSI_SERIALIZING & ~TRACE_DEBUG)
 */
 #define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
-       TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | \
-       TRACE_TIME)
+       TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_MINOR | \
+       TRACE_MGMT_DEBUG | TRACE_TIME)
 
 #define TRACE_SN(args...)      TRACE(TRACE_SCSI_SERIALIZING, args)
 
 #else /* DEBUG */
 
 # ifdef TRACING
-#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | \
+#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_MGMT \
        TRACE_TIME | TRACE_SPECIAL)
 # else
 #define DEFAULT_LOG_FLAGS 0
@@ -388,6 +388,9 @@ int main(int argc, char **argv)
        else
                desc.opt.prio_queue_type = SCST_USER_PRIO_QUEUE_SINGLE;
 
+       desc.opt.tst = SCST_CONTR_MODE_SEP_TASK_SETS;
+       desc.opt.queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
+
        res = ioctl(dev.scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
        if (res != 0) {
                res = errno;
@@ -418,7 +421,7 @@ int main(int argc, char **argv)
                res = ioctl(dev.scst_usr_fd, SCST_USER_SET_OPTIONS, &opt);
                if (res != 0) {
                        res = errno;
-                       PRINT_ERROR("Unable to get options: %s", strerror(res));
+                       PRINT_ERROR("Unable to set options: %s", strerror(res));
                        goto out_close;
                }
        }