- Now during connection and session reinstatements only SCSI commands are delayed...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Tue, 14 Apr 2009 17:29:23 +0000 (17:29 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Tue, 14 Apr 2009 17:29:23 +0000 (17:29 +0000)
 - TEST UNIT READY made HEAD OF QUEUE to let target don't look dead under high load
 - Docs updated

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

iscsi-scst/README
iscsi-scst/README_in-tree
iscsi-scst/kernel/conn.c
iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/nthread.c
iscsi-scst/kernel/session.c
iscsi-scst/kernel/target.c
scst/README
scst/README_in-tree
scst/src/scst_priv.h

index cd785a0..3c7cccf 100644 (file)
@@ -72,16 +72,17 @@ original IET behavior, when for data transmission:
 
  - For in-kernel allocated memory (scst_vdisk and pass-through
    handlers) usage of SGV cache on transmit path (READ-type commands)
-   will be disabled. The performance hit will be not big, but performance
-   will still remain better, than for IET, because SGV cache will remain
-   used on receive path while IET doesn't have such feature.
+   will be disabled, but data will still be sent in zero-copy manner.
+   The performance hit will be not big, but performance will still
+   remain better, than for IET, because SGV cache will remain used on
+   receive path while IET doesn't have such feature.
 
  - For user space allocated memory (scst_user handler) all transmitted
    data will be additionally copied into temporary TCP buffers. The
    performance hit will be quite noticeable.
 
 Note, that if your network hardware does not support TX offload
-functions of has them disabled, then TCP zero-copy transmit functions on
+functions or has them disabled, then TCP zero-copy transmit functions on
 your system will not be used by Linux networking in any case, so
 put_page_callback patch will not be able to improve performance for you.
 You can check your network hardware offload capabilities by command
@@ -131,6 +132,9 @@ and the SCST core as it logically should be: the target driver is
 responsible for handling targets and their parameters, SCST core is
 responsible for handling backstorage.
 
+It is recommended to use TEST UNIT READY ("tur") command to check if
+iSCSI-SCST target is alive.
+
 IMPORTANT: All LUN information (access control) MUST be configured
 =========  BEFORE iscsi-scstd started!
 
index 8cb04d8..4dafa89 100644 (file)
@@ -32,16 +32,17 @@ original IET behavior, when for data transmission:
 
  - For in-kernel allocated memory (scst_vdisk and pass-through
    handlers) usage of SGV cache on transmit path (READ-type commands)
-   will be disabled. The performance hit will be not big, but performance
-   will still remain better, than for IET, because SGV cache will remain
-   used on receive path while IET doesn't have such feature.
+   will be disabled, but data will still be sent in zero-copy manner.
+   The performance hit will be not big, but performance will still
+   remain better, than for IET, because SGV cache will remain used on
+   receive path while IET doesn't have such feature.
 
  - For user space allocated memory (scst_user handler) all transmitted
    data will be additionally copied into temporary TCP buffers. The
    performance hit will be quite noticeable.
 
 Note, that if your network hardware does not support TX offload
-functions of has them disabled, then TCP zero-copy transmit functions on
+functions or has them disabled, then TCP zero-copy transmit functions on
 your system will not be used by Linux networking in any case, so
 put_page_callback patch will not be able to improve performance for you.
 You can check your network hardware offload capabilities by command
@@ -66,6 +67,9 @@ and the SCST core as it logically should be: the target driver is
 responsible for handling targets and their parameters, SCST core is
 responsible for handling backstorage.
 
+It is recommended to use TEST UNIT READY ("tur") command to check if
+iSCSI-SCST target is alive.
+
 IMPORTANT: All LUN information (access control) MUST be configured
 =========  BEFORE iscsi-scstd started!
 
index 1f6e0a1..b60899f 100644 (file)
@@ -56,7 +56,7 @@ static void print_conn_state(char *p, size_t size, struct iscsi_conn *conn)
                break;
        }
 
-       if (conn->conn_reinstating)
+       if (test_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags))
                snprintf(p, size, "%s", "reinstating ");
        else if (!printed)
                snprintf(p, size, "%s", "established idle ");
@@ -132,8 +132,6 @@ static void iscsi_make_conn_rd_active(struct iscsi_conn *conn)
 {
        TRACE_ENTRY();
 
-       EXTRACHECKS_BUG_ON(conn->conn_reinstating);
-
        spin_lock_bh(&iscsi_rd_lock);
 
        TRACE_DBG("conn %p, rd_state %x, rd_data_ready %d", conn,
@@ -184,8 +182,7 @@ void __mark_conn_closed(struct iscsi_conn *conn, int flags)
                conn->deleting = 1;
        spin_unlock_bh(&iscsi_rd_lock);
 
-       if (!conn->conn_reinstating)
-               iscsi_make_conn_rd_active(conn);
+       iscsi_make_conn_rd_active(conn);
 }
 
 void mark_conn_closed(struct iscsi_conn *conn)
@@ -274,7 +271,7 @@ static void conn_rsp_timer_fn(unsigned long arg)
 
        if (!list_empty(&conn->written_list)) {
                struct iscsi_cmnd *wr_cmd = list_entry(conn->written_list.next,
-                               struct iscsi_cmnd, write_list_entry);
+                               struct iscsi_cmnd, written_list_entry);
 
                if (unlikely(time_after_eq(jiffies, wr_cmd->write_timeout))) {
                        if (!conn->closing) {
@@ -302,16 +299,34 @@ static void conn_rsp_timer_fn(unsigned long arg)
        return;
 }
 
-void __iscsi_socket_bind(struct iscsi_conn *conn)
+/* target_mutex supposed to be locked */
+void conn_reinst_finished(struct iscsi_conn *conn)
+{
+       struct iscsi_cmnd *cmnd, *t;
+
+       TRACE_ENTRY();
+
+       clear_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags);
+
+       list_for_each_entry_safe(cmnd, t, &conn->reinst_pending_cmd_list,
+                                       reinst_pending_cmd_list_entry) {
+               TRACE_MGMT_DBG("Restarting reinst pending cmnd %p",
+                       cmnd);
+               list_del(&cmnd->reinst_pending_cmd_list_entry);
+               iscsi_restart_cmnd(cmnd);
+       }
+
+       TRACE_EXIT();
+       return;
+}
+
+static void conn_activate(struct iscsi_conn *conn)
 {
        TRACE_MGMT_DBG("Enabling conn %p", conn);
 
        /* Catch double bind */
        sBUG_ON(conn->sock->sk->sk_state_change == iscsi_state_change);
 
-       /* Let's reset this flag in one place */
-       conn->conn_reinstating = 0;
-
        write_lock_bh(&conn->sock->sk->sk_callback_lock);
 
        conn->old_state_change = conn->sock->sk->sk_state_change;
@@ -340,7 +355,7 @@ void __iscsi_socket_bind(struct iscsi_conn *conn)
  * pointer. This seems to work fine, and this approach is also used in some
  * other parts of the Linux kernel (see e.g. fs/ocfs2/cluster/tcp.c).
  */
-static int iscsi_socket_bind(struct iscsi_conn *conn, bool reinstating)
+static int conn_setup_sock(struct iscsi_conn *conn)
 {
        int res = 0;
        int opt = 1;
@@ -369,17 +384,6 @@ static int iscsi_socket_bind(struct iscsi_conn *conn, bool reinstating)
                (void __force __user *)&opt, sizeof(opt));
        set_fs(oldfs);
 
-       if (!reinstating) {
-               /*
-                * We will delay full conn serving until all commands in
-                * replacing connections are done to prevent them from
-                * spoil our data by writing to them too late.
-                */
-               __iscsi_socket_bind(conn);
-       } else
-               TRACE_MGMT_DBG("conn %p is reinstating, delaying enabling it",
-                       conn);
-
 out:
        return res;
 }
@@ -399,9 +403,10 @@ int conn_free(struct iscsi_conn *conn)
        sBUG_ON(!list_empty(&conn->write_list));
        sBUG_ON(!list_empty(&conn->written_list));
        sBUG_ON(conn->conn_reinst_successor != NULL);
-       sBUG_ON(!conn->conn_shutting_down);
+       sBUG_ON(!test_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags));
 
-       if (conn->conn_reinstating) {
+       /* Just in case if new conn gets freed before the old one */
+       if (test_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags)) {
                struct iscsi_conn *c;
                TRACE_MGMT_DBG("Freeing being reinstated conn %p", conn);
                list_for_each_entry(c, &conn->session->conn_list,
@@ -428,14 +433,11 @@ int conn_free(struct iscsi_conn *conn)
 
 /* target_mutex supposed to be locked */
 static int iscsi_conn_alloc(struct iscsi_session *session,
-       struct iscsi_kern_conn_info *info, bool reinstating,
-       struct iscsi_conn **new_conn)
+       struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn)
 {
        struct iscsi_conn *conn;
        int res = 0;
 
-       reinstating |= session->sess_reinstating;
-
        conn = kzalloc(sizeof(*conn), GFP_KERNEL);
        if (!conn) {
                res = -ENOMEM;
@@ -454,7 +456,8 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
 
        atomic_set(&conn->conn_ref_cnt, 0);
        conn->session = session;
-       conn->conn_reinstating = reinstating;
+       if (session->sess_reinstating)
+               __set_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags);
        conn->cid = info->cid;
        conn->stat_sn = info->stat_sn;
        conn->exp_stat_sn = info->exp_stat_sn;
@@ -475,10 +478,11 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
        INIT_LIST_HEAD(&conn->written_list);
        setup_timer(&conn->rsp_timer, conn_rsp_timer_fn, (unsigned long)conn);
        init_completion(&conn->ready_to_free);
+       INIT_LIST_HEAD(&conn->reinst_pending_cmd_list);
 
        conn->file = fget(info->fd);
 
-       res = iscsi_socket_bind(conn, reinstating);
+       res = conn_setup_sock(conn);
        if (res != 0)
                goto out_err_free2;
 
@@ -510,7 +514,8 @@ int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
        bool reinstatement = false;
 
        conn = conn_lookup(session, info->cid);
-       if ((conn != NULL) && !conn->conn_shutting_down) {
+       if ((conn != NULL) &&
+           !test_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags)) {
                /* conn reinstatement */
                reinstatement = true;
        } else if (!list_empty(&session->conn_list)) {
@@ -518,7 +523,7 @@ int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
                goto out;
        }
 
-       err = iscsi_conn_alloc(session, info, reinstatement, &new_conn);
+       err = iscsi_conn_alloc(session, info, &new_conn);
        if (err != 0)
                goto out;
 
@@ -526,10 +531,12 @@ int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
                TRACE_MGMT_DBG("Reinstating conn (old %p, new %p)", conn,
                        new_conn);
                conn->conn_reinst_successor = new_conn;
-               new_conn->conn_reinstating = 1;
+               __set_bit(ISCSI_CONN_REINSTATING, &new_conn->conn_aflags);
                __mark_conn_closed(conn, 0);
        }
 
+       conn_activate(new_conn);
+
 out:
        return err;
 }
index 2e09be1..c4efbf1 100644 (file)
@@ -114,13 +114,45 @@ static inline int cmnd_read_size(struct iscsi_cmnd *cmnd)
        return 0;
 }
 
-static inline void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd)
+void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd)
 {
        EXTRACHECKS_BUG_ON(cmnd->data_waiting);
 
+       if (unlikely(test_bit(ISCSI_CONN_REINSTATING,
+                       &cmnd->conn->conn_aflags))) {
+               struct iscsi_target *target = cmnd->conn->session->target;
+               bool get_out;
+
+               mutex_lock(&target->target_mutex);
+
+               get_out = test_bit(ISCSI_CONN_REINSTATING,
+                               &cmnd->conn->conn_aflags);
+               /* Let's don't look dead */
+               if (scst_cmd_get_cdb(cmnd->scst_cmd)[0] == TEST_UNIT_READY)
+                       get_out = false;
+
+               if (!get_out)
+                       goto unlock_cont;
+
+               TRACE_MGMT_DBG("Pending cmnd %p, because conn %p is "
+                       "reinstated", cmnd, cmnd->conn);
+
+               cmnd->scst_state = ISCSI_CMD_STATE_REINST_PENDING;
+               list_add_tail(&cmnd->reinst_pending_cmd_list_entry,
+                       &cmnd->conn->reinst_pending_cmd_list);
+
+unlock_cont:
+               mutex_unlock(&target->target_mutex);
+
+               if (get_out)
+                       goto out;
+       }
+
        cmnd->scst_state = ISCSI_CMD_STATE_RESTARTED;
        scst_restart_cmd(cmnd->scst_cmd, SCST_PREPROCESS_STATUS_SUCCESS,
                SCST_CONTEXT_THREAD);
+
+out:
        return;
 }
 
@@ -226,6 +258,7 @@ static void cmnd_free(struct iscsi_cmnd *cmnd)
        return;
 }
 
+/* Might be called unded some lock and on SIRQ */
 void cmnd_done(struct iscsi_cmnd *cmnd)
 {
        TRACE_DBG("%p", cmnd);
@@ -243,7 +276,7 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
                TRACE_DBG("Deleting cmd %p from conn %p written_list", cmnd,
                        conn);
                spin_lock_bh(&conn->write_list_lock);
-               list_del(&cmnd->write_list_entry);
+               list_del(&cmnd->written_list_entry);
                cmnd->on_written_list = 0;
                spin_unlock_bh(&conn->write_list_lock);
        }
@@ -2973,7 +3006,7 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
 
        found = false;
        list_for_each_entry_reverse(conn, &sess->conn_list, conn_list_entry) {
-               if (!conn->conn_shutting_down &&
+               if (!test_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags) &&
                    (conn->conn_reinst_successor == NULL)) {
                        found = true;
                        break;
index 5ec817c..b9edf46 100644 (file)
@@ -147,6 +147,10 @@ struct iscsi_conn {
        u32 stat_sn;
        u32 exp_stat_sn;
 
+#define ISCSI_CONN_REINSTATING 1
+#define ISCSI_CONN_SHUTTINGDOWN        2
+       unsigned long conn_aflags;
+
        spinlock_t cmd_list_lock; /* BH lock */
 
        /* Protected by cmd_list_lock */
@@ -227,8 +231,7 @@ struct iscsi_conn {
 
        /* All protected by target_mutex, where necessary */
        struct iscsi_conn *conn_reinst_successor;
-       unsigned int conn_reinstating:1;
-       unsigned int conn_shutting_down:1;
+       struct list_head reinst_pending_cmd_list;
 
        struct completion ready_to_free;
 
@@ -257,14 +260,17 @@ typedef void (iscsi_show_info_t)(struct seq_file *seq,
 /* The command returned from preprocessing_done() */
 #define ISCSI_CMD_STATE_AFTER_PREPROC     2
 
+/* The command is waiting for session or connection reinstatement finished */
+#define ISCSI_CMD_STATE_REINST_PENDING    3
+
 /* scst_restart_cmd() called and SCST processing it */
-#define ISCSI_CMD_STATE_RESTARTED         3
+#define ISCSI_CMD_STATE_RESTARTED         4
 
 /* SCST done processing */
-#define ISCSI_CMD_STATE_PROCESSED         4
+#define ISCSI_CMD_STATE_PROCESSED         5
 
 /* AEN processing */
-#define ISCSI_CMD_STATE_AEN               5
+#define ISCSI_CMD_STATE_AEN               6
 
 /** Command's reject reasons **/
 #define ISCSI_REJECT_SCSI_CMD             1
@@ -320,7 +326,12 @@ struct iscsi_cmnd {
 
        union {
                struct list_head pending_list_entry;
+               struct list_head reinst_pending_cmd_list_entry;
+       };
+
+       union {
                struct list_head write_list_entry;
+               struct list_head written_list_entry;
        };
 
        /* Both modified only from single write thread */
@@ -410,10 +421,11 @@ extern void req_cmnd_release_force(struct iscsi_cmnd *req, int flags);
 extern void rsp_cmnd_release(struct iscsi_cmnd *);
 extern void cmnd_done(struct iscsi_cmnd *cmnd);
 extern void conn_abort(struct iscsi_conn *conn);
+extern void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd);
 
 /* conn.c */
 extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
-extern void __iscsi_socket_bind(struct iscsi_conn *);
+extern void conn_reinst_finished(struct iscsi_conn *);
 extern int conn_add(struct iscsi_session *, struct iscsi_kern_conn_info *);
 extern int conn_del(struct iscsi_session *, struct iscsi_kern_conn_info *);
 extern int conn_free(struct iscsi_conn *);
@@ -454,7 +466,7 @@ extern void iscsi_procfs_exit(void);
 /* session.c */
 extern const struct file_operations session_seq_fops;
 extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
-extern void sess_enable_reinstated_sess(struct iscsi_session *);
+extern void sess_reinst_finished(struct iscsi_session *);
 extern int session_add(struct iscsi_target *, struct iscsi_kern_session_info *);
 extern int session_del(struct iscsi_target *, u64);
 extern int session_free(struct iscsi_session *session, bool del);
index acc05d1..0ed8dcb 100644 (file)
@@ -339,11 +339,12 @@ void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd)
 
                mutex_lock(&sess->target->target_mutex);
                if (conn->conn_reinst_successor != NULL) {
-                       sBUG_ON(!conn->conn_reinst_successor->conn_reinstating);
-                       __iscsi_socket_bind(conn->conn_reinst_successor);
-                       /* We will check for conn_reinst_successor later */
+                       sBUG_ON(!test_bit(ISCSI_CONN_REINSTATING,
+                                 &conn->conn_reinst_successor->conn_aflags));
+                       conn_reinst_finished(conn->conn_reinst_successor);
+                       conn->conn_reinst_successor = NULL;
                } else if (sess->sess_reinst_successor != NULL) {
-                       sess_enable_reinstated_sess(sess->sess_reinst_successor);
+                       sess_reinst_finished(sess->sess_reinst_successor);
                        sess->sess_reinst_successor = NULL;
                }
                mutex_unlock(&sess->target->target_mutex);
@@ -394,12 +395,12 @@ static void close_conn(struct iscsi_conn *conn)
 
        mutex_lock(&session->target->target_mutex);
 
-       conn->conn_shutting_down = 1;
+       set_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags);
        reinst = (conn->conn_reinst_successor != NULL);
 
        session->sess_shutting_down = 1;
        list_for_each_entry(c, &session->conn_list, conn_list_entry) {
-               if (!c->conn_shutting_down) {
+               if (!test_bit(ISCSI_CONN_SHUTTINGDOWN, &c->conn_aflags)) {
                        session->sess_shutting_down = 0;
                        break;
                }
@@ -542,12 +543,8 @@ static void close_conn(struct iscsi_conn *conn)
                         conn);
        event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0);
 
-       sBUG_ON(conn->conn_reinstating);
-       sBUG_ON(session->sess_reinstating);
-
        mutex_lock(&target->target_mutex);
 
-       conn->conn_reinst_successor = NULL;
        conn_free(conn);
 
        if (list_empty(&session->conn_list)) {
@@ -1098,7 +1095,8 @@ static int write_data(struct iscsi_conn *conn)
                spin_lock_bh(&conn->write_list_lock);
                ref_cmd->on_written_list = 1;
                ref_cmd->write_timeout = jiffies + ISCSI_RSP_TIMEOUT;
-               list_add_tail(&ref_cmd->write_list_entry, &conn->written_list);
+               list_add_tail(&ref_cmd->written_list_entry,
+                       &conn->written_list);
                spin_unlock_bh(&conn->write_list_lock);
        }
 
index 8edac12..0cb15e5 100644 (file)
@@ -107,7 +107,7 @@ err:
 }
 
 /* target_mutex supposed to be locked */
-void sess_enable_reinstated_sess(struct iscsi_session *sess)
+void sess_reinst_finished(struct iscsi_session *sess)
 {
        struct iscsi_conn *c;
 
@@ -118,7 +118,7 @@ void sess_enable_reinstated_sess(struct iscsi_session *sess)
        sBUG_ON(!sess->sess_reinstating);
 
        list_for_each_entry(c, &sess->conn_list, conn_list_entry) {
-               __iscsi_socket_bind(c);
+               conn_reinst_finished(c);
        }
        sess->sess_reinstating = 0;
 
@@ -239,7 +239,7 @@ int session_free(struct iscsi_session *session, bool del)
                sBUG_ON(!list_empty(&session->cmnd_hash[i]));
 
        if (session->sess_reinst_successor != NULL)
-               sess_enable_reinstated_sess(session->sess_reinst_successor);
+               sess_reinst_finished(session->sess_reinst_successor);
 
        if (session->sess_reinstating) {
                struct iscsi_session *s;
index eaa9e42..b222d61 100644 (file)
@@ -184,6 +184,7 @@ out:
        return err;
 }
 
+/* target_mutex supposed to be locked */
 void target_del_session(struct iscsi_target *target,
        struct iscsi_session *session, int flags)
 {
index c24144b..c101efa 100644 (file)
@@ -57,20 +57,29 @@ corresponding to that symbol "#if LINUX_VERSION_CODE" statement.
 At first, make sure that the link "/lib/modules/`you_kernel_version`/build" 
 points to the source code for your currently running kernel.
 
-Then, since in the mainstream kernels scsi_do_req()/scsi_execute_async()
-work in LIFO order, instead of expected and required FIFO, SCST needs a
-new functions scsi_do_req_fifo()/scsi_execute_async_fifo() to be added
-in the kernel. Patch scst_exec_req_fifo.patch from "kernel" directory
-does that. If it doesn't apply to your kernel, apply it manually, it
-only adds one of those functions and nothing more. You may not patch the
-kernel if you don't need pass-through support or CONFIG_SCST_STRICT_SERIALIZING is
-defined during the compilation (see description below).
-
-Then, to get the maximum performance you should apply export_alloc_io_context
-patch. This patch simply makes alloc_io_context() function be available
-for modules, not only for built-in in kernel code.
-
-To compile SCST type 'make scst'. It will build SCST itself and its
+Then you should consider to apply necessary kernel patches. SCST has the
+following patches for the kernel in the "kernel" subdirectory. All of
+them are optional, so, if you don't need the corresponding
+functionality, you may not apply them.
+
+1. scst_exec_req_fifo-2.6.X.patch. This patch is necessary for
+pass-through dev handlers, because in the mainstream kernels
+scsi_do_req()/scsi_execute_async() work in LIFO order, instead of
+expected and required FIFO. So SCST needs new functions
+scsi_do_req_fifo() or scsi_execute_async_fifo() to be added in the
+kernel. This patch does that. You may not patch the kernel if you don't
+need pass-through support. Alternatively, you can define
+CONFIG_SCST_STRICT_SERIALIZING compile option during the compilation
+(see description below).
+
+2. io_context-2.6.X.patch. This patch exports some IO context management
+functions from the kernel. For performance reasons SCST queues commands
+using a pool of IO threads. It is considerably better for performance
+(>30% increase on sequential reads) if threads in a pool have the same
+IO context. This patch allows that. If you don't apply this patch, you
+will loose this performance benefit.
+
+Then, to compile SCST type 'make scst'. It will build SCST itself and its
 device handlers. To install them type 'make scst_install'. The driver
 modules will be installed in '/lib/modules/`you_kernel_version`/extra'.
 In addition, scst.h, scst_debug.h as well as Module.symvers or
@@ -139,6 +148,13 @@ IMPORTANT: In the current version simultaneous access to local SCSI devices
 To uninstall, type 'make scst_uninstall'.
 
 
+Usage in failover mode
+----------------------
+
+It is recommended to use TEST UNIT READY ("tur") command to check if
+SCST target is alive.
+
+
 Device handlers
 ---------------
 
@@ -236,9 +252,9 @@ in/out in Makefile:
    cases. The current SCSI core in Linux doesn't allow to abort all
    commands reliably if they sent asynchronously to a stateful device.
    Turned off by default, turn it on if you use stateful device(s) and
-   need as much error recovery reliability as possible. As a side
-   effect, no kernel patching is necessary for pass-through device
-   handlers (scst_disk, etc.).
+   need as much error recovery reliability as possible. As a side effect
+   of CONFIG_SCST_STRICT_SERIALIZING, no kernel patching is necessary
+   for pass-through device handlers (scst_disk, etc.).
 
  - CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
    allowed to submit pass-through commands to real SCSI devices via the SCSI
index eb525d5..0359e88 100644 (file)
@@ -83,6 +83,14 @@ IMPORTANT: In the current version simultaneous access to local SCSI devices
           devices READ/WRITE commands using direct disk handler look to
           be safe.
 
+
+Usage in failover mode
+----------------------
+
+It is recommended to use TEST UNIT READY ("tur") command to check if
+SCST target is alive.
+
+
 Device handlers
 ---------------
 
@@ -179,9 +187,9 @@ your favorit kernel configuration Makefile target, e.g. "make xconfig":
    cases. The current SCSI core in Linux doesn't allow to abort all
    commands reliably if they sent asynchronously to a stateful device.
    Turned off by default, turn it on if you use stateful device(s) and
-   need as much error recovery reliability as possible. As a side
-   effect, no kernel patching is necessary for pass-through device
-   handlers (scst_disk, etc.)
+   need as much error recovery reliability as possible. As a side effect
+   of CONFIG_SCST_STRICT_SERIALIZING, no kernel patching is necessary
+   for pass-through device handlers (scst_disk, etc.).
 
  - CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
    allowed to submit pass-through commands to real SCSI devices via the SCSI
index cffc46e..8fdb7cc 100644 (file)
@@ -415,19 +415,21 @@ void scst_process_reset(struct scst_device *dev,
 
 static inline int scst_is_ua_command(struct scst_cmd *cmd)
 {
-       return cmd->cdb[0] != INQUIRY
-              && cmd->cdb[0] != REQUEST_SENSE
-              && cmd->cdb[0] != REPORT_LUNS;
+       return (cmd->cdb[0] != INQUIRY) &&
+              (cmd->cdb[0] != REQUEST_SENSE) &&
+              (cmd->cdb[0] != REPORT_LUNS);
 }
 
 static inline int scst_is_implicit_hq(struct scst_cmd *cmd)
 {
-       return cmd->cdb[0] == INQUIRY
-              || cmd->cdb[0] == REPORT_LUNS
-              || (cmd->dev->type == TYPE_DISK
-                  && (cmd->cdb[0] == READ_CAPACITY
-                      || (cmd->cdb[0] == SERVICE_ACTION_IN
-                          && (cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16)));
+       return (cmd->cdb[0] == INQUIRY) ||
+              (cmd->cdb[0] == REPORT_LUNS) ||
+              ((cmd->dev->type == TYPE_DISK) &&
+                       ((cmd->cdb[0] == READ_CAPACITY) ||
+                        ((cmd->cdb[0] == SERVICE_ACTION_IN) &&
+                         ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16)))) ||
+              /* Let's don't look dead under high load */
+              (cmd->cdb[0] == TEST_UNIT_READY);
 }
 
 /*