diff --git a/iscsi-scst/README b/iscsi-scst/README index cd785a060..3c7cccf80 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -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! diff --git a/iscsi-scst/README_in-tree b/iscsi-scst/README_in-tree index 8cb04d8c1..4dafa8954 100644 --- a/iscsi-scst/README_in-tree +++ b/iscsi-scst/README_in-tree @@ -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! diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index 1f6e0a112..b60899f01 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -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; } diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 2e09be172..c4efbf1b1 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -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; diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 5ec817c4a..b9edf460d 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -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); diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index acc05d19d..0ed8dcb10 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -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); } diff --git a/iscsi-scst/kernel/session.c b/iscsi-scst/kernel/session.c index 8edac12a6..0cb15e531 100644 --- a/iscsi-scst/kernel/session.c +++ b/iscsi-scst/kernel/session.c @@ -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; diff --git a/iscsi-scst/kernel/target.c b/iscsi-scst/kernel/target.c index eaa9e426f..b222d615f 100644 --- a/iscsi-scst/kernel/target.c +++ b/iscsi-scst/kernel/target.c @@ -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) { diff --git a/scst/README b/scst/README index c24144bff..c101efad3 100644 --- a/scst/README +++ b/scst/README @@ -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 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. -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. +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). -To compile SCST type 'make scst'. It will build SCST itself and its +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 diff --git a/scst/README_in-tree b/scst/README_in-tree index eb525d5df..0359e8893 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -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 diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index cffc46eff..8fdb7cccd 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -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); } /*