mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-21 12:41:26 +00:00
A major locking and general code cleanup
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@90 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -150,12 +150,6 @@
|
||||
/* Thread context required for cmd's processing */
|
||||
#define SCST_CONTEXT_THREAD 3
|
||||
|
||||
/*
|
||||
* Additional bit to set processible environment.
|
||||
* Private for SCST, ie must not be used target drivers.
|
||||
*/
|
||||
#define SCST_PROCESSIBLE_ENV 0x10000000
|
||||
|
||||
/*************************************************************
|
||||
** Values for status parameter of scst_rx_data()
|
||||
*************************************************************/
|
||||
@@ -365,24 +359,30 @@
|
||||
*/
|
||||
#define SCST_CMD_XMITTING 4
|
||||
|
||||
/* Set if the cmd was done or aborted out of its SN */
|
||||
#define SCST_CMD_OUT_OF_SN 5
|
||||
|
||||
/* Set if the cmd is dead and can be destroyed at any time */
|
||||
#define SCST_CMD_CAN_BE_DESTROYED 6
|
||||
#define SCST_CMD_CAN_BE_DESTROYED 5
|
||||
|
||||
/*************************************************************
|
||||
** Tgt_dev's flags
|
||||
** Tgt_dev's flags (tgt_dev_flags)
|
||||
*************************************************************/
|
||||
|
||||
/* Set if tgt_dev has Unit Attention sense */
|
||||
#define SCST_TGT_DEV_UA_PENDING 0
|
||||
#define SCST_TGT_DEV_UA_PENDING 0
|
||||
|
||||
/* Set if tgt_dev is RESERVED by another session */
|
||||
#define SCST_TGT_DEV_RESERVED 1
|
||||
#define SCST_TGT_DEV_RESERVED 1
|
||||
|
||||
/* Set if the corresponding context is atomic */
|
||||
#define SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC 5
|
||||
#define SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC 6
|
||||
#define SCST_TGT_DEV_AFTER_RESTART_WR_ATOMIC 7
|
||||
#define SCST_TGT_DEV_AFTER_RESTART_OTH_ATOMIC 8
|
||||
#define SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC 9
|
||||
#define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 10
|
||||
|
||||
|
||||
#ifdef DEBUG_TM
|
||||
#define SCST_TGT_DEV_UNDER_TM_DBG 10
|
||||
#define SCST_TGT_DEV_UNDER_TM_DBG 20
|
||||
#endif
|
||||
|
||||
/*************************************************************
|
||||
@@ -657,9 +657,7 @@ struct scst_tgt_template
|
||||
* level driver. No return value expected.
|
||||
* This function is expected to be NON-BLOCKING
|
||||
*
|
||||
* Pay attention to "atomic" attribute of the cmd, which can be get
|
||||
* by scst_cmd_atomic(): it is true if the function called in the
|
||||
* atomic (non-sleeping) context.
|
||||
* Called without any locks held from a thread context.
|
||||
*
|
||||
* MUST HAVE if the target supports ABORTs
|
||||
*/
|
||||
@@ -838,7 +836,7 @@ struct scst_dev_type
|
||||
* - SCST_DEV_TM_NOT_COMPLETED - regular standard actions for the command
|
||||
* should be done
|
||||
*
|
||||
* Called with BH off. Might be called under a lock and IRQ off.
|
||||
* Called without any locks held from a thread context.
|
||||
*/
|
||||
int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd,
|
||||
struct scst_tgt_dev *tgt_dev);
|
||||
@@ -907,19 +905,13 @@ struct scst_session
|
||||
|
||||
atomic_t refcnt; /* get/put counter */
|
||||
|
||||
/* Alive commands for this session. Serialized by scst_list_lock */
|
||||
int sess_cmd_count;
|
||||
|
||||
/*************************************************************
|
||||
** Session's flags. Serialized by scst_list_lock
|
||||
** Session's flags. Serialized by scst_mgmt_lock
|
||||
*************************************************************/
|
||||
|
||||
/* Set if the session is shutting down */
|
||||
unsigned int shutting_down:1;
|
||||
|
||||
/* Set if the session is waiting in suspended state */
|
||||
unsigned int waiting:1;
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/*
|
||||
@@ -937,28 +929,22 @@ struct scst_session
|
||||
/* Used for storage of target driver private stuff */
|
||||
void *tgt_priv;
|
||||
|
||||
/* Alive commands for this session, protected by sess_list_lock */
|
||||
int sess_cmd_count;
|
||||
|
||||
spinlock_t sess_list_lock; /* protects search_cmd_list, etc */
|
||||
|
||||
/*
|
||||
* List of cmds in this session. Used to find a cmd in the
|
||||
* session. Protected by scst_list_lock.
|
||||
*
|
||||
* ToDo: make it protected by own lock.
|
||||
* session. Protected by sess_list_lock.
|
||||
*/
|
||||
struct list_head search_cmd_list;
|
||||
|
||||
struct scst_tgt *tgt; /* corresponding target */
|
||||
|
||||
/*
|
||||
* List entry for the list that keeps all sessions, which were
|
||||
* stopped due to device block
|
||||
*/
|
||||
struct list_head dev_wait_sess_list_entry;
|
||||
|
||||
/* Name of attached initiator */
|
||||
const char *initiator_name;
|
||||
|
||||
/* Used if scst_unregister_session() called in wait mode */
|
||||
struct completion *shutdown_compl;
|
||||
|
||||
/* List entry of sessions per target */
|
||||
struct list_head sess_list_entry;
|
||||
|
||||
@@ -967,11 +953,14 @@ struct scst_session
|
||||
|
||||
/*
|
||||
* Lists of deffered during session initialization commands.
|
||||
* Protected by scst_list_lock.
|
||||
* Protected by sess_list_lock.
|
||||
*/
|
||||
struct list_head init_deferred_cmd_list;
|
||||
struct list_head init_deferred_mcmd_list;
|
||||
|
||||
/* Used if scst_unregister_session() called in wait mode */
|
||||
struct completion *shutdown_compl;
|
||||
|
||||
/*
|
||||
* Functions and data for user callbacks from scst_register_session()
|
||||
* and scst_unregister_session()
|
||||
@@ -991,11 +980,24 @@ enum scst_cmd_queue_type
|
||||
SCST_CMD_QUEUE_ACA
|
||||
};
|
||||
|
||||
struct scst_cmd_lists
|
||||
{
|
||||
spinlock_t cmd_list_lock;
|
||||
struct list_head active_cmd_list;
|
||||
wait_queue_head_t cmd_list_waitQ;
|
||||
struct list_head lists_list_entry;
|
||||
};
|
||||
|
||||
struct scst_cmd
|
||||
{
|
||||
/* List entry for global *_cmd_list */
|
||||
/* List entry for below *_cmd_lists */
|
||||
struct list_head cmd_list_entry;
|
||||
|
||||
/* Pointer to lists of commands with the lock */
|
||||
struct scst_cmd_lists *cmd_lists;
|
||||
|
||||
atomic_t cmd_ref;
|
||||
|
||||
struct scst_session *sess; /* corresponding session */
|
||||
|
||||
/* Cmd state, one of SCST_CMD_STATE_* constants */
|
||||
@@ -1019,9 +1021,6 @@ struct scst_cmd
|
||||
/* Set if cmd is being processed in atomic context */
|
||||
unsigned int atomic:1;
|
||||
|
||||
/* Set if cmd must be processed only in non-atomic context */
|
||||
unsigned int non_atomic_only:1;
|
||||
|
||||
/* Set if cmd is internally generated */
|
||||
unsigned int internal:1;
|
||||
|
||||
@@ -1047,14 +1046,6 @@ struct scst_cmd
|
||||
/* Set if the target driver called scst_set_expected() */
|
||||
unsigned int expected_values_set:1;
|
||||
|
||||
/*
|
||||
* Set if the cmd is being processed from the thread/tasklet,
|
||||
* i.e. if another cmd is moved to the active list during processing
|
||||
* of the current one, then another cmd will be processed after
|
||||
* the current. Helps to save some context switches.
|
||||
*/
|
||||
unsigned int processible_env:1;
|
||||
|
||||
/*
|
||||
* Set if the cmd was delayed by task management debugging code.
|
||||
* Used only if DEBUG_TM is on.
|
||||
@@ -1100,9 +1091,12 @@ struct scst_cmd
|
||||
*/
|
||||
unsigned int may_need_dma_sync:1;
|
||||
|
||||
/* Set if the cmd was done or aborted out of its SN */
|
||||
unsigned long out_of_sn:1;
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
unsigned long cmd_flags; /* cmd's async flags */
|
||||
unsigned long cmd_flags; /* cmd's async flags */
|
||||
|
||||
struct scst_tgt_template *tgtt; /* to save extra dereferences */
|
||||
struct scst_tgt *tgt; /* to save extra dereferences */
|
||||
@@ -1190,7 +1184,7 @@ struct scst_cmd
|
||||
|
||||
uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* sense buffer */
|
||||
|
||||
/* The corresponding mgmt cmd, if any. Protected by scst_list_lock */
|
||||
/* The corresponding mgmt cmd, if any, protected by sess_list_lock */
|
||||
struct scst_mgmt_cmd *mgmt_cmnd;
|
||||
|
||||
/* List entry for dev's blocked_cmd_list */
|
||||
@@ -1227,11 +1221,15 @@ struct scst_mgmt_cmd
|
||||
int fn;
|
||||
|
||||
unsigned int completed:1; /* set, if the mcmd is completed */
|
||||
unsigned int active:1; /* set, if the mcmd is active */
|
||||
|
||||
/* Number of commands to complete before sending response */
|
||||
/*
|
||||
* Number of commands to complete before sending response,
|
||||
* protected by scst_mcmd_lock
|
||||
*/
|
||||
int cmd_wait_count;
|
||||
|
||||
/* Number of completed commands */
|
||||
/* Number of completed commands, protected by scst_mcmd_lock */
|
||||
int completed_cmd_count;
|
||||
|
||||
lun_t lun; /* LUN for this mgmt cmd */
|
||||
@@ -1334,11 +1332,8 @@ struct scst_tgt_dev
|
||||
|
||||
struct scst_acg_dev *acg_dev; /* corresponding acg_dev */
|
||||
|
||||
/*
|
||||
* How many cmds alive on this dev in this session.
|
||||
* Protected by scst_list_lock.
|
||||
*/
|
||||
int cmd_count;
|
||||
/* How many cmds alive on this dev in this session */
|
||||
atomic_t cmd_count;
|
||||
|
||||
spinlock_t tgt_dev_lock; /* per-session device lock */
|
||||
|
||||
@@ -1350,16 +1345,19 @@ struct scst_tgt_dev
|
||||
/* Used for storage of dev handler private stuff */
|
||||
void *dh_priv;
|
||||
|
||||
/* Pointer to lists of commands with the lock */
|
||||
struct scst_cmd_lists *p_cmd_lists;
|
||||
|
||||
/*
|
||||
* Used to execute cmd's in order of arrival.
|
||||
*
|
||||
* Protected by sn_lock, except next_sn and expected_sn.
|
||||
* Protected by sn_lock, except curr_sn and expected_sn.
|
||||
* Expected_sn protected by itself, since only one thread, which
|
||||
* processes SN matching command, can increment it at any time.
|
||||
* Next_sn must be the same type as expected_sn to overflow
|
||||
* Next_sn must have the same size as expected_sn to overflow
|
||||
* simultaneously.
|
||||
*/
|
||||
int next_sn; /* protected by scst_list_lock */
|
||||
atomic_t curr_sn;
|
||||
int expected_sn;
|
||||
spinlock_t sn_lock;
|
||||
int def_cmd_count;
|
||||
|
||||
@@ -2325,7 +2325,7 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Called with BH off. Might be called under lock and IRQ off */
|
||||
/* No locks supposed to be held, thread context */
|
||||
static int fileio_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
||||
struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
@@ -2338,12 +2338,7 @@ static int fileio_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
||||
struct scst_fileio_tgt_dev *ftgt_dev =
|
||||
(struct scst_fileio_tgt_dev *)cmd_to_abort->tgt_dev->dh_priv;
|
||||
|
||||
/*
|
||||
* It is safe relating to scst_list_lock despite of lockdep's
|
||||
* warning. Just don't know how to tell it to lockdep.
|
||||
*/
|
||||
/* BH already off */
|
||||
spin_lock(&ftgt_dev->fdev_lock);
|
||||
spin_lock_bh(&ftgt_dev->fdev_lock);
|
||||
if (cmd_to_abort->fileio_in_list) {
|
||||
TRACE(TRACE_MGMT, "Aborting cmd %p and moving it to "
|
||||
"the queue head", cmd_to_abort);
|
||||
@@ -2352,7 +2347,7 @@ static int fileio_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
||||
&ftgt_dev->fdev_cmd_list);
|
||||
wake_up(&ftgt_dev->fdev_waitQ);
|
||||
}
|
||||
spin_unlock(&ftgt_dev->fdev_lock);
|
||||
spin_unlock_bh(&ftgt_dev->fdev_lock);
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
|
||||
290
scst/src/scst.c
290
scst/src/scst.c
@@ -32,23 +32,18 @@
|
||||
#include "scst_priv.h"
|
||||
#include "scst_mem.h"
|
||||
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
unsigned long scst_trace_flag = SCST_DEFAULT_LOG_FLAGS;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All targets, devices and dev_types management is done under
|
||||
* this mutex.
|
||||
*/
|
||||
DECLARE_MUTEX(scst_mutex);
|
||||
|
||||
DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ);
|
||||
LIST_HEAD(scst_dev_wait_sess_list);
|
||||
|
||||
LIST_HEAD(scst_template_list);
|
||||
LIST_HEAD(scst_dev_list);
|
||||
LIST_HEAD(scst_dev_type_list);
|
||||
|
||||
spinlock_t scst_main_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
struct kmem_cache *scst_mgmt_cachep;
|
||||
mempool_t *scst_mgmt_mempool;
|
||||
struct kmem_cache *scst_ua_cachep;
|
||||
@@ -60,32 +55,37 @@ struct kmem_cache *scst_acgd_cachep;
|
||||
LIST_HEAD(scst_acg_list);
|
||||
struct scst_acg *scst_default_acg;
|
||||
|
||||
spinlock_t scst_init_lock = SPIN_LOCK_UNLOCKED;
|
||||
DECLARE_WAIT_QUEUE_HEAD(scst_init_cmd_list_waitQ);
|
||||
LIST_HEAD(scst_init_cmd_list);
|
||||
unsigned int scst_init_poll_cnt;
|
||||
|
||||
struct kmem_cache *scst_cmd_cachep;
|
||||
|
||||
#if defined(DEBUG) || defined(TRACING)
|
||||
unsigned long scst_trace_flag = SCST_DEFAULT_LOG_FLAGS;
|
||||
#endif
|
||||
|
||||
unsigned long scst_flags;
|
||||
atomic_t scst_cmd_count = ATOMIC_INIT(0);
|
||||
spinlock_t scst_list_lock = SPIN_LOCK_UNLOCKED;
|
||||
LIST_HEAD(scst_active_cmd_list);
|
||||
LIST_HEAD(scst_init_cmd_list);
|
||||
LIST_HEAD(scst_cmd_list);
|
||||
DECLARE_WAIT_QUEUE_HEAD(scst_list_waitQ);
|
||||
|
||||
spinlock_t scst_cmd_mem_lock = SPIN_LOCK_UNLOCKED;
|
||||
unsigned long scst_cur_cmd_mem, scst_cur_max_cmd_mem;
|
||||
|
||||
struct tasklet_struct scst_tasklets[NR_CPUS];
|
||||
unsigned long scst_max_cmd_mem;
|
||||
|
||||
struct scst_sgv_pools scst_sgv;
|
||||
|
||||
struct scst_cmd_lists scst_main_cmd_lists;
|
||||
|
||||
struct scst_tasklet scst_tasklets[NR_CPUS];
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
||||
DECLARE_WORK(scst_cmd_mem_work, scst_cmd_mem_work_fn, 0);
|
||||
#else
|
||||
DECLARE_DELAYED_WORK(scst_cmd_mem_work, scst_cmd_mem_work_fn);
|
||||
#endif
|
||||
|
||||
unsigned long scst_max_cmd_mem;
|
||||
|
||||
LIST_HEAD(scst_mgmt_cmd_list);
|
||||
spinlock_t scst_mcmd_lock = SPIN_LOCK_UNLOCKED;
|
||||
LIST_HEAD(scst_active_mgmt_cmd_list);
|
||||
LIST_HEAD(scst_delayed_mgmt_cmd_list);
|
||||
DECLARE_WAIT_QUEUE_HEAD(scst_mgmt_cmd_list_waitQ);
|
||||
@@ -94,6 +94,11 @@ DECLARE_WAIT_QUEUE_HEAD(scst_mgmt_waitQ);
|
||||
spinlock_t scst_mgmt_lock = SPIN_LOCK_UNLOCKED;
|
||||
LIST_HEAD(scst_sess_mgmt_list);
|
||||
|
||||
DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ);
|
||||
|
||||
DECLARE_MUTEX(scst_suspend_mutex);;
|
||||
LIST_HEAD(scst_cmd_lists_list); /* protected by scst_suspend_mutex */
|
||||
|
||||
static int scst_threads;
|
||||
struct scst_threads_info_t scst_threads_info;
|
||||
|
||||
@@ -152,6 +157,9 @@ int scst_register_target_template(struct scst_tgt_template *vtt)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (vtt->preprocessing_done == NULL)
|
||||
vtt->preprocessing_done_atomic = 1;
|
||||
|
||||
if (down_interruptible(&m) != 0)
|
||||
goto out_err;
|
||||
|
||||
@@ -265,6 +273,7 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt)
|
||||
tgt->retry_timer.data = (unsigned long)tgt;
|
||||
tgt->retry_timer.function = scst_tgt_retry_timer_fn;
|
||||
|
||||
scst_suspend_activity();
|
||||
down(&scst_mutex);
|
||||
|
||||
if (scst_build_proc_target_entries(tgt) < 0) {
|
||||
@@ -275,6 +284,7 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt)
|
||||
list_add_tail(&tgt->tgt_list_entry, &vtt->tgt_list);
|
||||
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
PRINT_INFO_PR("Target for template %s registered successfully",
|
||||
vtt->name);
|
||||
@@ -285,6 +295,7 @@ out:
|
||||
|
||||
out_up:
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
out_err:
|
||||
PRINT_ERROR_PR("Failed to register target for template %s", vtt->name);
|
||||
@@ -321,12 +332,16 @@ void scst_unregister(struct scst_tgt *tgt)
|
||||
wait_event(tgt->unreg_waitQ, test_sess_list(tgt));
|
||||
TRACE_DBG("%s", "wait_event() returned");
|
||||
|
||||
scst_suspend_activity();
|
||||
down(&scst_mutex);
|
||||
|
||||
list_del(&tgt->tgt_list_entry);
|
||||
up(&scst_mutex);
|
||||
|
||||
scst_cleanup_proc_target_entries(tgt);
|
||||
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
del_timer_sync(&tgt->retry_timer);
|
||||
|
||||
kfree(tgt);
|
||||
@@ -338,72 +353,81 @@ void scst_unregister(struct scst_tgt *tgt)
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
void __scst_suspend_activity(void)
|
||||
void scst_suspend_activity(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
down(&scst_suspend_mutex);
|
||||
|
||||
TRACE_MGMT_DBG("suspend_count %d", suspend_count);
|
||||
suspend_count++;
|
||||
if (suspend_count > 1)
|
||||
goto out;
|
||||
goto out_up;
|
||||
|
||||
set_bit(SCST_FLAG_SUSPENDING, &scst_flags);
|
||||
set_bit(SCST_FLAG_SUSPENDED, &scst_flags);
|
||||
smp_mb__after_set_bit();
|
||||
|
||||
TRACE_DBG("Waiting for all %d active commands to complete",
|
||||
TRACE_MGMT_DBG("Waiting for %d active commands to complete",
|
||||
atomic_read(&scst_cmd_count));
|
||||
wait_event(scst_dev_cmd_waitQ, atomic_read(&scst_cmd_count) == 0);
|
||||
TRACE_DBG("%s", "wait_event() returned");
|
||||
TRACE_MGMT_DBG("%s", "wait_event() returned");
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
void scst_suspend_activity(void)
|
||||
{
|
||||
down(&scst_mutex);
|
||||
__scst_suspend_activity();
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
void __scst_resume_activity(void)
|
||||
{
|
||||
struct scst_session *sess, *tsess;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
suspend_count--;
|
||||
if (suspend_count > 0)
|
||||
goto out;
|
||||
|
||||
clear_bit(SCST_FLAG_SUSPENDED, &scst_flags);
|
||||
clear_bit(SCST_FLAG_SUSPENDING, &scst_flags);
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
spin_lock_irq(&scst_list_lock);
|
||||
list_for_each_entry_safe(sess, tsess, &scst_dev_wait_sess_list,
|
||||
dev_wait_sess_list_entry)
|
||||
{
|
||||
sess->waiting = 0;
|
||||
list_del(&sess->dev_wait_sess_list_entry);
|
||||
}
|
||||
spin_unlock_irq(&scst_list_lock);
|
||||
TRACE_MGMT_DBG("Waiting for %d active commands finally to complete",
|
||||
atomic_read(&scst_cmd_count));
|
||||
wait_event(scst_dev_cmd_waitQ, atomic_read(&scst_cmd_count) == 0);
|
||||
TRACE_MGMT_DBG("%s", "wait_event() returned");
|
||||
|
||||
wake_up_all(&scst_list_waitQ);
|
||||
wake_up_all(&scst_mgmt_cmd_list_waitQ);
|
||||
out_up:
|
||||
up(&scst_suspend_mutex);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
void scst_resume_activity(void)
|
||||
{
|
||||
__scst_resume_activity();
|
||||
up(&scst_mutex);
|
||||
struct scst_cmd_lists *l;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
down(&scst_suspend_mutex);
|
||||
|
||||
TRACE_MGMT_DBG("suspend_count %d", suspend_count);
|
||||
suspend_count--;
|
||||
if (suspend_count > 0)
|
||||
goto out_up;
|
||||
|
||||
clear_bit(SCST_FLAG_SUSPENDED, &scst_flags);
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
list_for_each_entry(l, &scst_cmd_lists_list, lists_list_entry) {
|
||||
wake_up_all(&l->cmd_list_waitQ);
|
||||
}
|
||||
wake_up_all(&scst_init_cmd_list_waitQ);
|
||||
|
||||
spin_lock_irq(&scst_mcmd_lock);
|
||||
if (!list_empty(&scst_delayed_mgmt_cmd_list)) {
|
||||
struct scst_mgmt_cmd *m;
|
||||
m = list_entry(scst_delayed_mgmt_cmd_list.next, typeof(*m),
|
||||
mgmt_cmd_list_entry);
|
||||
TRACE_MGMT_DBG("Moving delayed mgmt cmd %p to head of active "
|
||||
"mgmt cmd list", m);
|
||||
list_move(&m->mgmt_cmd_list_entry, &scst_active_mgmt_cmd_list);
|
||||
}
|
||||
spin_unlock_irq(&scst_mcmd_lock);
|
||||
wake_up_all(&scst_mgmt_cmd_list_waitQ);
|
||||
|
||||
out_up:
|
||||
up(&scst_suspend_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Called under scst_mutex */
|
||||
static int scst_register_device(struct scsi_device *scsidp)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -412,12 +436,15 @@ static int scst_register_device(struct scsi_device *scsidp)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_suspend_activity();
|
||||
down(&scst_mutex);
|
||||
|
||||
dev = scst_alloc_device(GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
|
||||
dev->rq_disk = alloc_disk(1);
|
||||
if (dev->rq_disk == NULL) {
|
||||
res = -ENOMEM;
|
||||
@@ -438,7 +465,10 @@ static int scst_register_device(struct scsi_device *scsidp)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
out_up:
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
if (res == 0) {
|
||||
PRINT_INFO_PR("Attached SCSI target mid-level at "
|
||||
"scsi%d, channel %d, id %d, lun %d, type %d",
|
||||
@@ -461,10 +491,9 @@ out_free:
|
||||
|
||||
out_free_dev:
|
||||
scst_free_device(dev);
|
||||
goto out;
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
/* Called under scst_mutex */
|
||||
static void scst_unregister_device(struct scsi_device *scsidp)
|
||||
{
|
||||
struct scst_device *d, *dev = NULL;
|
||||
@@ -472,7 +501,8 @@ static void scst_unregister_device(struct scsi_device *scsidp)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
__scst_suspend_activity();
|
||||
scst_suspend_activity();
|
||||
down(&scst_mutex);
|
||||
|
||||
list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
|
||||
if (d->scsi_dev == scsidp) {
|
||||
@@ -504,16 +534,39 @@ static void scst_unregister_device(struct scsi_device *scsidp)
|
||||
scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
|
||||
|
||||
out_unblock:
|
||||
__scst_resume_activity();
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (dev_handler->parse == NULL) {
|
||||
PRINT_ERROR_PR("scst dev_type driver %s doesn't have a "
|
||||
"parse() method.", dev_handler->name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev_handler->exec == NULL)
|
||||
dev_handler->exec_atomic = 1;
|
||||
|
||||
if (dev_handler->dev_done == NULL)
|
||||
dev_handler->dev_done_atomic = 1;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int scst_register_virtual_device(struct scst_dev_type *dev_handler,
|
||||
const char *dev_name)
|
||||
{
|
||||
int res = -EINVAL, rc;
|
||||
int res, rc;
|
||||
struct scst_device *dev = NULL;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -531,6 +584,10 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = scst_dev_handler_check(dev_handler);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
dev = scst_alloc_device(GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
res = -ENOMEM;
|
||||
@@ -540,6 +597,8 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
|
||||
dev->scsi_dev = NULL;
|
||||
dev->virt_name = dev_name;
|
||||
|
||||
scst_suspend_activity();
|
||||
|
||||
if (down_interruptible(&scst_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out_free_dev;
|
||||
@@ -559,6 +618,9 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
|
||||
|
||||
up(&scst_mutex);
|
||||
|
||||
out_resume:
|
||||
scst_resume_activity();
|
||||
|
||||
out:
|
||||
if (res > 0) {
|
||||
PRINT_INFO_PR("Attached SCSI target mid-level to virtual "
|
||||
@@ -578,7 +640,7 @@ out_free_del:
|
||||
|
||||
out_free_dev:
|
||||
scst_free_device(dev);
|
||||
goto out;
|
||||
goto out_resume;
|
||||
}
|
||||
|
||||
void scst_unregister_virtual_device(int id)
|
||||
@@ -588,10 +650,9 @@ void scst_unregister_virtual_device(int id)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_suspend_activity();
|
||||
down(&scst_mutex);
|
||||
|
||||
__scst_suspend_activity();
|
||||
|
||||
list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
|
||||
if (d->virt_id == id) {
|
||||
dev = d;
|
||||
@@ -620,9 +681,8 @@ void scst_unregister_virtual_device(int id)
|
||||
scst_free_device(dev);
|
||||
|
||||
out_unblock:
|
||||
__scst_resume_activity();
|
||||
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -632,17 +692,14 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
|
||||
{
|
||||
struct scst_dev_type *dt;
|
||||
struct scst_device *dev;
|
||||
int res = 0;
|
||||
int res;
|
||||
int exist;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (dev_type->parse == NULL) {
|
||||
PRINT_ERROR_PR("scst dev_type driver %s doesn't have a "
|
||||
"parse() method.", dev_type->name);
|
||||
res = -EINVAL;
|
||||
res = scst_dev_handler_check(dev_type);
|
||||
if (res != 0)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
#ifdef FILEIO_ONLY
|
||||
if (dev_type->exec == NULL) {
|
||||
@@ -654,6 +711,8 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
|
||||
}
|
||||
#endif
|
||||
|
||||
scst_suspend_activity();
|
||||
|
||||
if (down_interruptible(&scst_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out_err;
|
||||
@@ -678,16 +737,15 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
|
||||
|
||||
list_add_tail(&dev_type->dev_type_list_entry, &scst_dev_type_list);
|
||||
|
||||
__scst_suspend_activity();
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
if ((dev->scsi_dev == NULL) || (dev->handler != NULL))
|
||||
continue;
|
||||
if (dev->scsi_dev->type == dev_type->type)
|
||||
scst_assign_dev_handler(dev, dev_type);
|
||||
}
|
||||
__scst_resume_activity();
|
||||
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
if (res == 0) {
|
||||
PRINT_INFO_PR("Device handler %s for type %d registered "
|
||||
@@ -702,6 +760,7 @@ out_up:
|
||||
up(&scst_mutex);
|
||||
|
||||
out_err:
|
||||
scst_resume_activity();
|
||||
PRINT_ERROR_PR("Failed to register device handler %s for type %d",
|
||||
dev_type->name, dev_type->type);
|
||||
goto out;
|
||||
@@ -715,6 +774,7 @@ void scst_unregister_dev_driver(struct scst_dev_type *dev_type)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_suspend_activity();
|
||||
down(&scst_mutex);
|
||||
|
||||
list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
|
||||
@@ -729,18 +789,17 @@ void scst_unregister_dev_driver(struct scst_dev_type *dev_type)
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
__scst_suspend_activity();
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
if (dev->handler == dev_type) {
|
||||
scst_assign_dev_handler(dev, NULL);
|
||||
TRACE_DBG("Dev handler removed from device %p", dev);
|
||||
}
|
||||
}
|
||||
__scst_resume_activity();
|
||||
|
||||
list_del(&dev_type->dev_type_list_entry);
|
||||
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
scst_cleanup_proc_dev_handler_dir_entries(dev_type);
|
||||
|
||||
@@ -753,21 +812,19 @@ out:
|
||||
|
||||
out_up:
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
goto out;
|
||||
}
|
||||
|
||||
int scst_register_virtual_dev_driver(struct scst_dev_type *dev_type)
|
||||
{
|
||||
int res = 0;
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (dev_type->parse == NULL) {
|
||||
PRINT_ERROR_PR("scst dev_type driver %s doesn't have a "
|
||||
"parse() method.", dev_type->name);
|
||||
res = -EINVAL;
|
||||
res = scst_dev_handler_check(dev_type);
|
||||
if (res != 0)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = scst_build_proc_dev_handler_dir_entries(dev_type);
|
||||
if (res < 0)
|
||||
@@ -799,7 +856,7 @@ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type)
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_assign_dev_handler(struct scst_device *dev,
|
||||
struct scst_dev_type *handler)
|
||||
{
|
||||
@@ -812,8 +869,6 @@ int scst_assign_dev_handler(struct scst_device *dev,
|
||||
if (dev->handler == handler)
|
||||
goto out;
|
||||
|
||||
__scst_suspend_activity();
|
||||
|
||||
if (dev->handler && dev->handler->detach_tgt) {
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry)
|
||||
@@ -841,7 +896,7 @@ int scst_assign_dev_handler(struct scst_device *dev,
|
||||
PRINT_ERROR_PR("New device handler's %s attach() "
|
||||
"failed: %d", handler->name, res);
|
||||
}
|
||||
goto out_resume;
|
||||
goto out_null;
|
||||
}
|
||||
|
||||
if (handler && handler->attach_tgt) {
|
||||
@@ -862,10 +917,9 @@ int scst_assign_dev_handler(struct scst_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
out_resume:
|
||||
out_null:
|
||||
if (res != 0)
|
||||
dev->handler = NULL;
|
||||
__scst_resume_activity();
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -885,9 +939,9 @@ out_err_detach_tgt:
|
||||
if (handler && handler->detach) {
|
||||
TRACE_DBG("%s", "Calling handler's detach()");
|
||||
handler->detach(dev);
|
||||
TRACE_DBG("%s", "Hhandler's detach() returned");
|
||||
TRACE_DBG("%s", "Handler's detach() returned");
|
||||
}
|
||||
goto out_resume;
|
||||
goto out_null;
|
||||
}
|
||||
|
||||
int scst_cmd_threads_count(void)
|
||||
@@ -959,7 +1013,8 @@ int __scst_add_cmd_threads(int num)
|
||||
PRINT_ERROR_PR("fail to allocate thr %d", res);
|
||||
goto out_error;
|
||||
}
|
||||
thr->cmd_thread = kthread_run(scst_cmd_thread, 0, "scsi_tgt%d",
|
||||
thr->cmd_thread = kthread_run(scst_cmd_thread,
|
||||
&scst_main_cmd_lists, "scsi_tgt%d",
|
||||
scst_thread_num++);
|
||||
if (IS_ERR(thr->cmd_thread)) {
|
||||
res = PTR_ERR(thr->cmd_thread);
|
||||
@@ -1019,6 +1074,8 @@ static void scst_stop_all_threads(void)
|
||||
kthread_stop(scst_threads_info.mgmt_cmd_thread);
|
||||
if (scst_threads_info.mgmt_thread)
|
||||
kthread_stop(scst_threads_info.mgmt_thread);
|
||||
if (scst_threads_info.init_cmd_thread)
|
||||
kthread_stop(scst_threads_info.init_cmd_thread);
|
||||
up(&scst_threads_info.cmd_threads_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
@@ -1036,6 +1093,15 @@ static int scst_start_all_threads(int num)
|
||||
if (res < 0)
|
||||
goto out;
|
||||
|
||||
scst_threads_info.init_cmd_thread = kthread_run(scst_init_cmd_thread,
|
||||
NULL, "scsi_tgt_init");
|
||||
if (IS_ERR(scst_threads_info.init_cmd_thread)) {
|
||||
res = PTR_ERR(scst_threads_info.init_cmd_thread);
|
||||
PRINT_ERROR_PR("kthread_create() for init cmd failed: %d", res);
|
||||
scst_threads_info.init_cmd_thread = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
scst_threads_info.mgmt_cmd_thread = kthread_run(scst_mgmt_cmd_thread,
|
||||
NULL, "scsi_tgt_mc");
|
||||
if (IS_ERR(scst_threads_info.mgmt_cmd_thread)) {
|
||||
@@ -1062,12 +1128,12 @@ out:
|
||||
|
||||
void scst_get(void)
|
||||
{
|
||||
scst_inc_cmd_count();
|
||||
__scst_get(0);
|
||||
}
|
||||
|
||||
void scst_put(void)
|
||||
{
|
||||
scst_dec_cmd_count();
|
||||
__scst_put();
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
|
||||
@@ -1082,10 +1148,7 @@ static int scst_add(struct class_device *cdev, struct class_interface *intf)
|
||||
TRACE_ENTRY();
|
||||
|
||||
scsidp = to_scsi_device(cdev->dev);
|
||||
|
||||
down(&scst_mutex);
|
||||
res = scst_register_device(scsidp);
|
||||
up(&scst_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return res;
|
||||
@@ -1102,10 +1165,7 @@ static void scst_remove(struct class_device *cdev, struct class_interface *intf)
|
||||
TRACE_ENTRY();
|
||||
|
||||
scsidp = to_scsi_device(cdev->dev);
|
||||
|
||||
down(&scst_mutex);
|
||||
scst_unregister_device(scsidp);
|
||||
up(&scst_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -1137,6 +1197,16 @@ static int __init init_scst(void)
|
||||
(sizeof(cmd->sense_buffer) >= SCSI_SENSE_BUFFERSIZE));
|
||||
}
|
||||
#endif
|
||||
{
|
||||
struct scst_tgt_dev *t;
|
||||
BUILD_BUG_ON(sizeof(t->curr_sn) != sizeof(t->expected_sn));
|
||||
}
|
||||
|
||||
spin_lock_init(&scst_main_cmd_lists.cmd_list_lock);
|
||||
INIT_LIST_HEAD(&scst_main_cmd_lists.active_cmd_list);
|
||||
init_waitqueue_head(&scst_main_cmd_lists.cmd_list_waitQ);
|
||||
list_add_tail(&scst_main_cmd_lists.lists_list_entry,
|
||||
&scst_cmd_lists_list);
|
||||
|
||||
scst_num_cpus = num_online_cpus();
|
||||
|
||||
@@ -1204,8 +1274,12 @@ static int __init init_scst(void)
|
||||
|
||||
scst_scsi_op_list_init();
|
||||
|
||||
for (i = 0; i < sizeof(scst_tasklets)/sizeof(scst_tasklets[0]); i++)
|
||||
tasklet_init(&scst_tasklets[i], (void *)scst_cmd_tasklet, 0);
|
||||
for (i = 0; i < sizeof(scst_tasklets)/sizeof(scst_tasklets[0]); i++) {
|
||||
spin_lock_init(&scst_tasklets[i].tasklet_lock);
|
||||
INIT_LIST_HEAD(&scst_tasklets[i].tasklet_cmd_list);
|
||||
tasklet_init(&scst_tasklets[i].tasklet, (void*)scst_cmd_tasklet,
|
||||
(unsigned long)&scst_tasklets[i]);
|
||||
}
|
||||
|
||||
TRACE_DBG("%d CPUs found, starting %d threads", scst_num_cpus,
|
||||
scst_threads);
|
||||
|
||||
@@ -84,21 +84,22 @@ void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
|
||||
|
||||
void scst_set_busy(struct scst_cmd *cmd)
|
||||
{
|
||||
int c = cmd->sess->sess_cmd_count;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if ((cmd->sess->sess_cmd_count <= 1) ||
|
||||
(cmd->sess->init_phase != SCST_SESS_IPH_READY))
|
||||
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 "
|
||||
"(cmds count %d, queue_type %x, sess->init_phase %d)",
|
||||
cmd->sess->initiator_name, cmd->sess->sess_cmd_count,
|
||||
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, cmd->sess->sess_cmd_count,
|
||||
cmd->sess->initiator_name, c,
|
||||
cmd->queue_type, cmd->sess->init_phase);
|
||||
}
|
||||
|
||||
@@ -218,7 +219,7 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
void scst_free_acg_dev(struct scst_acg_dev *acg_dev)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
@@ -234,7 +235,7 @@ void scst_free_acg_dev(struct scst_acg_dev *acg_dev)
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
struct scst_acg *scst_alloc_add_acg(const char *acg_name)
|
||||
{
|
||||
struct scst_acg *acg;
|
||||
@@ -260,7 +261,7 @@ out:
|
||||
return acg;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_destroy_acg(struct scst_acg *acg)
|
||||
{
|
||||
struct scst_acn *n, *nn;
|
||||
@@ -275,8 +276,6 @@ int scst_destroy_acg(struct scst_acg *acg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
__scst_suspend_activity();
|
||||
|
||||
TRACE_DBG("Removing acg %s from scst_acg_list", acg->acg_name);
|
||||
list_del(&acg->scst_acg_list_entry);
|
||||
|
||||
@@ -295,8 +294,6 @@ int scst_destroy_acg(struct scst_acg *acg)
|
||||
scst_free_acg_dev(acg_dev);
|
||||
}
|
||||
|
||||
__scst_resume_activity();
|
||||
|
||||
/* Freeing names */
|
||||
list_for_each_entry_safe(n, nn, &acg->acn_list,
|
||||
acn_list_entry)
|
||||
@@ -342,8 +339,12 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
|
||||
tgt_dev->acg_dev = acg_dev;
|
||||
tgt_dev->sess = sess;
|
||||
tgt_dev->cmd_count = 0;
|
||||
atomic_set(&tgt_dev->cmd_count, 0);
|
||||
atomic_set(&tgt_dev->curr_sn, 0);
|
||||
tgt_dev->expected_sn = 1;
|
||||
|
||||
tgt_dev->p_cmd_lists = &scst_main_cmd_lists;
|
||||
|
||||
if (dev->scsi_dev != NULL) {
|
||||
TRACE(TRACE_DEBUG, "host=%d, channel=%d, id=%d, lun=%d, "
|
||||
"SCST lun=%Ld", dev->scsi_dev->host->host_no,
|
||||
@@ -361,6 +362,30 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
INIT_LIST_HEAD(&tgt_dev->deferred_cmd_list);
|
||||
INIT_LIST_HEAD(&tgt_dev->skipped_sn_list);
|
||||
|
||||
if (dev->handler->parse_atomic &&
|
||||
sess->tgt->tgtt->preprocessing_done_atomic) {
|
||||
if (sess->tgt->tgtt->rdy_to_xfer_atomic)
|
||||
__set_bit(SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
if (dev->handler->exec_atomic)
|
||||
__set_bit(SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
if (dev->handler->exec_atomic) {
|
||||
if (sess->tgt->tgtt->rdy_to_xfer_atomic)
|
||||
__set_bit(SCST_TGT_DEV_AFTER_RESTART_WR_ATOMIC,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
__set_bit(SCST_TGT_DEV_AFTER_RESTART_OTH_ATOMIC,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
__set_bit(SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
if (dev->handler->dev_done_atomic &&
|
||||
sess->tgt->tgtt->xmit_response_atomic) {
|
||||
__set_bit(SCST_TGT_DEV_AFTER_EXEC_ATOMIC,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
|
||||
spin_lock_bh(&scst_temp_UA_lock);
|
||||
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
|
||||
SCST_LOAD_SENSE(scst_sense_reset_UA));
|
||||
@@ -467,7 +492,7 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_sess_alloc_tgt_devs(struct scst_session *sess)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -476,8 +501,6 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
__scst_suspend_activity();
|
||||
|
||||
INIT_LIST_HEAD(&sess->sess_tgt_dev_list);
|
||||
list_for_each_entry(acg_dev, &sess->acg->acg_dev_list,
|
||||
acg_dev_list_entry)
|
||||
@@ -489,15 +512,13 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess)
|
||||
}
|
||||
}
|
||||
|
||||
out_resume:
|
||||
__scst_resume_activity();
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return res;
|
||||
|
||||
out_free:
|
||||
scst_sess_free_tgt_devs(sess);
|
||||
goto out_resume;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held and activity suspended */
|
||||
@@ -519,7 +540,7 @@ void scst_sess_free_tgt_devs(struct scst_session *sess)
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun,
|
||||
int read_only)
|
||||
{
|
||||
@@ -551,8 +572,6 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun,
|
||||
}
|
||||
acg_dev->rd_only_flag = read_only;
|
||||
|
||||
__scst_suspend_activity();
|
||||
|
||||
TRACE_DBG("Adding acg_dev %p to acg_dev_list and dev_acg_dev_list",
|
||||
acg_dev);
|
||||
list_add_tail(&acg_dev->acg_dev_list_entry, &acg->acg_dev_list);
|
||||
@@ -569,9 +588,6 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun,
|
||||
&tmp_tgt_dev_list);
|
||||
}
|
||||
|
||||
out_resume:
|
||||
__scst_resume_activity();
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
@@ -583,10 +599,10 @@ out_free:
|
||||
scst_free_tgt_dev(tgt_dev);
|
||||
}
|
||||
scst_free_acg_dev(acg_dev);
|
||||
goto out_resume;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -608,8 +624,6 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
__scst_suspend_activity();
|
||||
|
||||
list_for_each_entry_safe(tgt_dev, tt, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry)
|
||||
{
|
||||
@@ -618,8 +632,6 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
|
||||
}
|
||||
scst_free_acg_dev(acg_dev);
|
||||
|
||||
__scst_resume_activity();
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
@@ -715,6 +727,7 @@ struct scst_cmd *scst_create_prepare_internal_cmd(
|
||||
goto out;
|
||||
}
|
||||
|
||||
res->cmd_lists = orig_cmd->cmd_lists;
|
||||
res->sess = orig_cmd->sess;
|
||||
res->state = SCST_CMD_STATE_SEND_TO_MIDLEV;
|
||||
res->atomic = scst_cmd_atomic(orig_cmd);
|
||||
@@ -750,9 +763,7 @@ void scst_free_internal_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (cmd->bufflen > 0)
|
||||
scst_release_space(cmd);
|
||||
scst_destroy_cmd(cmd);
|
||||
scst_cmd_put(cmd);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -760,7 +771,7 @@ void scst_free_internal_cmd(struct scst_cmd *cmd)
|
||||
|
||||
int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
|
||||
{
|
||||
int res = SCST_CMD_STATE_RES_RESTART;
|
||||
int res = SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
#define sbuf_size 252
|
||||
static const unsigned char request_sense[6] =
|
||||
{ REQUEST_SENSE, 0, 0, 0, sbuf_size, 0 };
|
||||
@@ -776,9 +787,11 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
|
||||
rs_cmd->cdb_len = sizeof(request_sense);
|
||||
rs_cmd->data_direction = SCST_DATA_READ;
|
||||
|
||||
spin_lock_irq(&scst_list_lock);
|
||||
list_add(&rs_cmd->cmd_list_entry, &scst_active_cmd_list);
|
||||
spin_unlock_irq(&scst_list_lock);
|
||||
TRACE(TRACE_RETRY, "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);
|
||||
spin_unlock_irq(&rs_cmd->cmd_lists->cmd_list_lock);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -949,11 +962,12 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
|
||||
sess->init_phase = SCST_SESS_IPH_INITING;
|
||||
atomic_set(&sess->refcnt, 0);
|
||||
INIT_LIST_HEAD(&sess->sess_tgt_dev_list);
|
||||
spin_lock_init(&sess->sess_list_lock);
|
||||
INIT_LIST_HEAD(&sess->search_cmd_list);
|
||||
sess->tgt = tgt;
|
||||
INIT_LIST_HEAD(&sess->init_deferred_cmd_list);
|
||||
INIT_LIST_HEAD(&sess->init_deferred_mcmd_list);
|
||||
|
||||
|
||||
len = strlen(initiator_name);
|
||||
nm = kmalloc(len + 1, gfp_mask);
|
||||
if (nm == NULL) {
|
||||
@@ -978,19 +992,20 @@ void scst_free_session(struct scst_session *sess)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_suspend_activity();
|
||||
down(&scst_mutex);
|
||||
|
||||
TRACE_DBG("Removing sess %p from the list", sess);
|
||||
list_del(&sess->sess_list_entry);
|
||||
TRACE_DBG("Removing session %p from acg %s", sess, sess->acg->acg_name);
|
||||
list_del(&sess->acg_sess_list_entry);
|
||||
|
||||
__scst_suspend_activity();
|
||||
|
||||
scst_sess_free_tgt_devs(sess);
|
||||
__scst_resume_activity();
|
||||
|
||||
wake_up_all(&sess->tgt->unreg_waitQ);
|
||||
|
||||
up(&scst_mutex);
|
||||
scst_resume_activity();
|
||||
|
||||
kfree(sess->initiator_name);
|
||||
kmem_cache_free(scst_sess_cachep, sess);
|
||||
@@ -1059,6 +1074,8 @@ struct scst_cmd *scst_alloc_cmd(int gfp_mask)
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
#endif
|
||||
|
||||
atomic_set(&cmd->cmd_ref, 1);
|
||||
cmd->cmd_lists = &scst_main_cmd_lists;
|
||||
cmd->queue_type = SCST_CMD_QUEUE_UNTAGGED;
|
||||
cmd->timeout = SCST_DEFAULT_TIMEOUT;
|
||||
cmd->retries = 1;
|
||||
@@ -1071,19 +1088,19 @@ out:
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static void scst_destroy_put_cmd(struct scst_cmd *cmd)
|
||||
void scst_destroy_put_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
scst_sess_put(cmd->sess);
|
||||
|
||||
/* At this point tgt_dev can be dead, but the pointer remains not-NULL */
|
||||
if (likely(cmd->tgt_dev != NULL))
|
||||
scst_dec_cmd_count();
|
||||
__scst_put();
|
||||
|
||||
scst_destroy_cmd(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No locks supposed to be held. Must be called only from scst_finish_cmd()! */
|
||||
/* No locks supposed to be held */
|
||||
void scst_free_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
int destroy = 1;
|
||||
@@ -1100,6 +1117,24 @@ void scst_free_cmd(struct scst_cmd *cmd)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (likely(cmd->tgt_dev != NULL))
|
||||
atomic_dec(&cmd->tgt_dev->cmd_count);
|
||||
|
||||
/*
|
||||
* cmd->mgmt_cmnd can't being changed here, since for that it either
|
||||
* must be on search_cmd_list, or cmd_ref must be taken. Both are
|
||||
* false here.
|
||||
*/
|
||||
if (unlikely(cmd->mgmt_cmnd))
|
||||
scst_complete_cmd_mgmt(cmd, cmd->mgmt_cmnd);
|
||||
|
||||
if (unlikely(cmd->internal)) {
|
||||
if (cmd->bufflen > 0)
|
||||
scst_release_space(cmd);
|
||||
scst_destroy_cmd(cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cmd->tgtt->on_free_cmd != NULL) {
|
||||
TRACE_DBG("Calling target's on_free_cmd(%p)", cmd);
|
||||
cmd->tgtt->on_free_cmd(cmd);
|
||||
@@ -1126,34 +1161,29 @@ void scst_free_cmd(struct scst_cmd *cmd)
|
||||
"target %s, lun %Ld, sn %d, expected_sn %d)",
|
||||
cmd->cdb[0], cmd->tgtt->name, (uint64_t)cmd->lun,
|
||||
cmd->sn, cmd->tgt_dev->expected_sn);
|
||||
scst_inc_expected_sn_unblock(cmd->tgt_dev, cmd, 0);
|
||||
scst_inc_expected_sn_unblock(cmd->tgt_dev, cmd);
|
||||
}
|
||||
#endif
|
||||
if (unlikely(test_bit(SCST_CMD_OUT_OF_SN,
|
||||
&cmd->cmd_flags)))
|
||||
{
|
||||
spin_lock_bh(&cmd->tgt_dev->sn_lock);
|
||||
set_bit(SCST_CMD_CAN_BE_DESTROYED,
|
||||
&cmd->cmd_flags);
|
||||
barrier(); /* to reread SCST_CMD_OUT_OF_SN */
|
||||
destroy = !test_bit(SCST_CMD_OUT_OF_SN,
|
||||
&cmd->cmd_flags);
|
||||
|
||||
if (unlikely(cmd->out_of_sn)) {
|
||||
TRACE(TRACE_SCSI_SERIALIZING, "Out of SN "
|
||||
"cmd %p (tag %d, sn %d), destroy=%d", cmd,
|
||||
cmd->tag, cmd->sn, destroy);
|
||||
spin_unlock_bh(&cmd->tgt_dev->sn_lock);
|
||||
destroy = test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED,
|
||||
&cmd->cmd_flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(destroy))
|
||||
scst_destroy_put_cmd(cmd);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* No locks supposed to be held. */
|
||||
void scst_check_retries(struct scst_tgt *tgt, int processible_env)
|
||||
void scst_check_retries(struct scst_tgt *tgt)
|
||||
{
|
||||
int need_wake_up = 0;
|
||||
|
||||
@@ -1174,29 +1204,25 @@ void scst_check_retries(struct scst_tgt *tgt, int processible_env)
|
||||
tgt->retry_cmds);
|
||||
|
||||
spin_lock_irqsave(&tgt->tgt_lock, flags);
|
||||
spin_lock(&scst_list_lock);
|
||||
|
||||
list_for_each_entry_safe(c, tc, &tgt->retry_cmd_list,
|
||||
cmd_list_entry)
|
||||
{
|
||||
tgt->retry_cmds--;
|
||||
|
||||
TRACE(TRACE_RETRY, "Moving retry cmd %p to active cmd "
|
||||
"list (retry_cmds left %d)", c, tgt->retry_cmds);
|
||||
list_move(&c->cmd_list_entry, &scst_active_cmd_list);
|
||||
TRACE(TRACE_RETRY, "Moving retry cmd %p to head of active "
|
||||
"cmd list (retry_cmds left %d)", c, tgt->retry_cmds);
|
||||
spin_lock(&c->cmd_lists->cmd_list_lock);
|
||||
list_move(&c->cmd_list_entry, &c->cmd_lists->active_cmd_list);
|
||||
wake_up(&c->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&c->cmd_lists->cmd_list_lock);
|
||||
|
||||
need_wake_up++;
|
||||
if (need_wake_up >= 2) /* "slow start" */
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&scst_list_lock);
|
||||
spin_unlock_irqrestore(&tgt->tgt_lock, flags);
|
||||
}
|
||||
|
||||
if (need_wake_up && !processible_env)
|
||||
wake_up(&scst_list_waitQ);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
@@ -1213,7 +1239,7 @@ void scst_tgt_retry_timer_fn(unsigned long arg)
|
||||
tgt->retry_timer_active = 0;
|
||||
spin_unlock_irqrestore(&tgt->tgt_lock, flags);
|
||||
|
||||
scst_check_retries(tgt, 0);
|
||||
scst_check_retries(tgt);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -1238,22 +1264,20 @@ out:
|
||||
return mcmd;
|
||||
}
|
||||
|
||||
void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd, int del)
|
||||
void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
spin_lock_irqsave(&scst_list_lock, flags);
|
||||
if (del)
|
||||
list_del(&mcmd->mgmt_cmd_list_entry);
|
||||
spin_lock_irqsave(&mcmd->sess->sess_list_lock, flags);
|
||||
mcmd->sess->sess_cmd_count--;
|
||||
spin_unlock_irqrestore(&scst_list_lock, flags);
|
||||
spin_unlock_irqrestore(&mcmd->sess->sess_list_lock, flags);
|
||||
|
||||
scst_sess_put(mcmd->sess);
|
||||
|
||||
if (mcmd->mcmd_tgt_dev != NULL)
|
||||
scst_dec_cmd_count();
|
||||
__scst_put();
|
||||
|
||||
mempool_free(mcmd, scst_mgmt_mempool);
|
||||
|
||||
@@ -1722,7 +1746,6 @@ void scst_process_reset(struct scst_device *dev,
|
||||
{
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct scst_cmd *cmd, *tcmd;
|
||||
int wake = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -1759,8 +1782,7 @@ void scst_process_reset(struct scst_device *dev,
|
||||
{
|
||||
struct scst_session *sess = tgt_dev->sess;
|
||||
|
||||
local_bh_disable();
|
||||
spin_lock_irq(&scst_list_lock);
|
||||
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,
|
||||
@@ -1774,27 +1796,23 @@ void scst_process_reset(struct scst_device *dev,
|
||||
(tgt_dev->sess != originator), 0);
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&scst_list_lock);
|
||||
local_bh_enable();
|
||||
spin_unlock_irq(&sess->sess_list_lock);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list,
|
||||
blocked_cmd_list_entry) {
|
||||
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
list_del(&cmd->blocked_cmd_list_entry);
|
||||
TRACE_MGMT_DBG("Moving aborted blocked cmd %p "
|
||||
TRACE_MGMT_DBG("Adding aborted blocked cmd %p "
|
||||
"to active cmd list", cmd);
|
||||
spin_lock_irq(&scst_list_lock);
|
||||
list_move_tail(&cmd->cmd_list_entry,
|
||||
&scst_active_cmd_list);
|
||||
spin_unlock_irq(&scst_list_lock);
|
||||
wake = 1;
|
||||
spin_lock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (wake)
|
||||
wake_up(&scst_list_waitQ);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
@@ -1992,12 +2010,9 @@ restart:
|
||||
tcmd->tag, tcmd->sn);
|
||||
tgt_dev->def_cmd_count--;
|
||||
list_del(&tcmd->sn_cmd_list_entry);
|
||||
if (test_bit(SCST_CMD_CAN_BE_DESTROYED,
|
||||
if (test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED,
|
||||
&tcmd->cmd_flags)) {
|
||||
scst_destroy_put_cmd(tcmd);
|
||||
} else {
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(SCST_CMD_OUT_OF_SN, &tcmd->cmd_flags);
|
||||
}
|
||||
expected_sn = __scst_inc_expected_sn(tgt_dev);
|
||||
goto restart;
|
||||
@@ -2091,10 +2106,10 @@ void scst_unblock_cmds(struct scst_device *dev)
|
||||
{
|
||||
#ifdef STRICT_SERIALIZING
|
||||
struct scst_cmd *cmd, *t;
|
||||
int found = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
local_irq_save(flags);
|
||||
list_for_each_entry_safe(cmd, t, &dev->blocked_cmd_list,
|
||||
blocked_cmd_list_entry) {
|
||||
unsigned long flags;
|
||||
@@ -2117,62 +2132,64 @@ void scst_unblock_cmds(struct scst_device *dev)
|
||||
}
|
||||
|
||||
list_del(&cmd->blocked_cmd_list_entry);
|
||||
TRACE_MGMT_DBG("Moving cmd %p to active cmd list", cmd);
|
||||
spin_lock_irqsave(&scst_list_lock, flags);
|
||||
list_move(&cmd->cmd_list_entry, &scst_active_cmd_list);
|
||||
spin_unlock_irqrestore(&scst_list_lock, flags);
|
||||
found = 1;
|
||||
TRACE_MGMT_DBG("Adding cmd %p to head of active cmd list", cmd);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
list_add(&cmd->cmd_list_entry, &cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
if (brk)
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
wake_up(&scst_list_waitQ);
|
||||
local_irq_restore(, flags);
|
||||
#else /* STRICT_SERIALIZING */
|
||||
struct scst_cmd *cmd, *tcmd;
|
||||
unsigned long flags;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
spin_lock_irqsave(&scst_list_lock, flags);
|
||||
local_irq_save(flags);
|
||||
list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list,
|
||||
blocked_cmd_list_entry) {
|
||||
list_del(&cmd->blocked_cmd_list_entry);
|
||||
TRACE_MGMT_DBG("Moving blocked cmd %p to active cmd list", cmd);
|
||||
list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list);
|
||||
wake_up(&scst_list_waitQ);
|
||||
TRACE_MGMT_DBG("Adding blocked cmd %p to active cmd list", cmd);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
}
|
||||
spin_unlock_irqrestore(&scst_list_lock, flags);
|
||||
local_irq_restore(flags);
|
||||
#endif /* STRICT_SERIALIZING */
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static struct scst_cmd *scst_inc_expected_sn(
|
||||
static struct scst_cmd *__scst_inc_expected_sn_unblock(
|
||||
struct scst_tgt_dev *tgt_dev, struct scst_cmd *out_of_sn_cmd)
|
||||
{
|
||||
struct scst_cmd *res = NULL;
|
||||
|
||||
if (out_of_sn_cmd->sn == tgt_dev->expected_sn) {
|
||||
__scst_inc_expected_sn(tgt_dev);
|
||||
res = scst_check_deferred_commands(tgt_dev,
|
||||
tgt_dev->expected_sn);
|
||||
} else {
|
||||
out_of_sn_cmd->out_of_sn = 1;
|
||||
spin_lock_bh(&tgt_dev->sn_lock);
|
||||
tgt_dev->def_cmd_count++;
|
||||
set_bit(SCST_CMD_OUT_OF_SN, &out_of_sn_cmd->cmd_flags);
|
||||
list_add_tail(&out_of_sn_cmd->sn_cmd_list_entry,
|
||||
&tgt_dev->skipped_sn_list);
|
||||
TRACE(TRACE_SCSI_SERIALIZING, "out_of_sn_cmd %p with sn %d "
|
||||
"added to skipped_sn_list (expected_sn %d)",
|
||||
out_of_sn_cmd, out_of_sn_cmd->sn, tgt_dev->expected_sn);
|
||||
spin_unlock_bh(&tgt_dev->sn_lock);
|
||||
smp_mb(); /* just in case, we need new value of tgt_dev->expected_sn */
|
||||
}
|
||||
res = scst_check_deferred_commands(tgt_dev, tgt_dev->expected_sn);
|
||||
return res;
|
||||
}
|
||||
|
||||
void scst_inc_expected_sn_unblock(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_cmd *out_of_sn_cmd, int locked)
|
||||
struct scst_cmd *out_of_sn_cmd)
|
||||
{
|
||||
struct scst_cmd *cmd;
|
||||
|
||||
@@ -2183,18 +2200,15 @@ void scst_inc_expected_sn_unblock(struct scst_tgt_dev *tgt_dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd = scst_inc_expected_sn(tgt_dev, out_of_sn_cmd);
|
||||
cmd = __scst_inc_expected_sn_unblock(tgt_dev, out_of_sn_cmd);
|
||||
if (cmd != NULL) {
|
||||
unsigned long flags = 0;
|
||||
if (!locked)
|
||||
spin_lock_irqsave(&scst_list_lock, flags);
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
|
||||
TRACE(TRACE_SCSI_SERIALIZING, "cmd %p with sn %d "
|
||||
"moved to active cmd list", cmd, cmd->sn);
|
||||
list_move(&cmd->cmd_list_entry, &scst_active_cmd_list);
|
||||
if (!locked)
|
||||
spin_unlock_irqrestore(&scst_list_lock, flags);
|
||||
if (!out_of_sn_cmd->processible_env)
|
||||
wake_up(&scst_list_waitQ);
|
||||
"added to the head of active cmd list", cmd, cmd->sn);
|
||||
list_add(&cmd->cmd_list_entry, &cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irqrestore(&cmd->cmd_lists->cmd_list_lock, flags);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -2223,7 +2237,6 @@ void __init scst_scsi_op_list_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Original taken from the XFS code */
|
||||
unsigned long scst_random(void)
|
||||
@@ -2263,111 +2276,140 @@ unsigned long scst_random(void)
|
||||
|
||||
static void tm_dbg_timer_fn(unsigned long arg);
|
||||
|
||||
/* All serialized by scst_list_lock */
|
||||
static int tm_dbg_release;
|
||||
static int tm_dbg_blocked;
|
||||
static spinlock_t scst_tm_dbg_lock = SPIN_LOCK_UNLOCKED;
|
||||
/* All serialized by scst_tm_dbg_lock */
|
||||
struct
|
||||
{
|
||||
unsigned int tm_dbg_active:1;
|
||||
unsigned int tm_dbg_release:1;
|
||||
unsigned int tm_dbg_blocked:1;
|
||||
} tm_dbg_flags;
|
||||
static LIST_HEAD(tm_dbg_delayed_cmd_list);
|
||||
static int tm_dbg_delayed_cmds_count;
|
||||
static int tm_dbg_passed_cmds_count;
|
||||
static int tm_dbg_state;
|
||||
static int tm_dbg_on_state_passes;
|
||||
static DEFINE_TIMER(tm_dbg_timer, tm_dbg_timer_fn, 0, 0);
|
||||
static wait_queue_head_t *tm_dbg_p_cmd_list_waitQ;
|
||||
|
||||
static const int tm_dbg_on_state_num_passes[] = { 5, 1, 0x7ffffff };
|
||||
|
||||
void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_acg_dev *acg_dev)
|
||||
{
|
||||
if ((acg_dev->acg == scst_default_acg) && (acg_dev->lun == 0)) {
|
||||
/* Do TM debugging only for LUN 0 */
|
||||
tm_dbg_state = INIT_TM_DBG_STATE;
|
||||
tm_dbg_on_state_passes =
|
||||
tm_dbg_on_state_num_passes[tm_dbg_state];
|
||||
__set_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags);
|
||||
PRINT_INFO("LUN 0 connected from initiator %s is under "
|
||||
"TM debugging", tgt_dev->sess->tgt->tgtt->name);
|
||||
if (((acg_dev->acg == scst_default_acg) ||
|
||||
(acg_dev->acg == tgt_dev->sess->tgt->default_acg)) &&
|
||||
(acg_dev->lun == 0)) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
if (!tm_dbg_flags.tm_dbg_active) {
|
||||
/* Do TM debugging only for LUN 0 */
|
||||
tm_dbg_p_cmd_list_waitQ =
|
||||
&tgt_dev->p_cmd_lists->cmd_list_waitQ;
|
||||
tm_dbg_state = INIT_TM_DBG_STATE;
|
||||
tm_dbg_on_state_passes =
|
||||
tm_dbg_on_state_num_passes[tm_dbg_state];
|
||||
__set_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags);
|
||||
PRINT_INFO("LUN 0 connected from initiator %s is under "
|
||||
"TM debugging", tgt_dev->sess->tgt->tgtt->name);
|
||||
tm_dbg_flags.tm_dbg_active = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
if (test_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags))
|
||||
if (test_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags)) {
|
||||
unsigned long flags;
|
||||
del_timer_sync(&tm_dbg_timer);
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
tm_dbg_p_cmd_list_waitQ = NULL;
|
||||
tm_dbg_flags.tm_dbg_active = 0;
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void tm_dbg_timer_fn(unsigned long arg)
|
||||
{
|
||||
TRACE_MGMT_DBG("%s: delayed cmd timer expired", __func__);
|
||||
tm_dbg_release = 1;
|
||||
TRACE_MGMT_DBG("%s", "delayed cmd timer expired");
|
||||
tm_dbg_flags.tm_dbg_release = 1;
|
||||
smp_mb();
|
||||
wake_up_all(&scst_list_waitQ);
|
||||
wake_up_all(tm_dbg_p_cmd_list_waitQ);
|
||||
}
|
||||
|
||||
/* Called under scst_list_lock */
|
||||
/* Called under scst_tm_dbg_lock and IRQs off */
|
||||
static void tm_dbg_delay_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
switch(tm_dbg_state) {
|
||||
case TM_DBG_STATE_ABORT:
|
||||
if (tm_dbg_delayed_cmds_count == 0) {
|
||||
unsigned long d = 58*HZ + (scst_random() % (4*HZ));
|
||||
TRACE_MGMT_DBG("%s: delaying timed cmd %p (tag %d) "
|
||||
TRACE_MGMT_DBG("STATE ABORT: delaying cmd %p (tag %d) "
|
||||
"for %ld.%ld seconds (%ld HZ), "
|
||||
"tm_dbg_on_state_passes=%d", __func__, cmd,
|
||||
cmd->tag, d/HZ, (d%HZ)*100/HZ, d,
|
||||
tm_dbg_on_state_passes);
|
||||
"tm_dbg_on_state_passes=%d", cmd, cmd->tag,
|
||||
d/HZ, (d%HZ)*100/HZ, d, tm_dbg_on_state_passes);
|
||||
mod_timer(&tm_dbg_timer, jiffies + d);
|
||||
#if 0
|
||||
tm_dbg_blocked = 1;
|
||||
tm_dbg_flags.tm_dbg_blocked = 1;
|
||||
#endif
|
||||
} else {
|
||||
TRACE_MGMT_DBG("%s: delaying another timed cmd %p "
|
||||
TRACE_MGMT_DBG("Delaying another timed cmd %p "
|
||||
"(tag %d), delayed_cmds_count=%d, "
|
||||
"tm_dbg_on_state_passes=%d", __func__, cmd,
|
||||
cmd->tag, tm_dbg_delayed_cmds_count,
|
||||
"tm_dbg_on_state_passes=%d", cmd, cmd->tag,
|
||||
tm_dbg_delayed_cmds_count,
|
||||
tm_dbg_on_state_passes);
|
||||
if (tm_dbg_delayed_cmds_count == 2)
|
||||
tm_dbg_blocked = 0;
|
||||
tm_dbg_flags.tm_dbg_blocked = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case TM_DBG_STATE_RESET:
|
||||
case TM_DBG_STATE_OFFLINE:
|
||||
TRACE_MGMT_DBG("%s: delaying cmd %p "
|
||||
TRACE_MGMT_DBG("STATE RESET/OFFLINE: delaying cmd %p "
|
||||
"(tag %d), delayed_cmds_count=%d, "
|
||||
"tm_dbg_on_state_passes=%d", __func__, cmd,
|
||||
cmd->tag, tm_dbg_delayed_cmds_count,
|
||||
tm_dbg_on_state_passes);
|
||||
tm_dbg_blocked = 1;
|
||||
"tm_dbg_on_state_passes=%d", cmd, cmd->tag,
|
||||
tm_dbg_delayed_cmds_count, tm_dbg_on_state_passes);
|
||||
tm_dbg_flags.tm_dbg_blocked = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
sBUG();
|
||||
}
|
||||
list_move_tail(&cmd->cmd_list_entry, &tm_dbg_delayed_cmd_list);
|
||||
/* IRQs already off */
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
list_add_tail(&cmd->cmd_list_entry, &tm_dbg_delayed_cmd_list);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
cmd->tm_dbg_delayed = 1;
|
||||
tm_dbg_delayed_cmds_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Called under scst_list_lock */
|
||||
/* No locks */
|
||||
void tm_dbg_check_released_cmds(void)
|
||||
{
|
||||
if (tm_dbg_release) {
|
||||
if (tm_dbg_flags.tm_dbg_release) {
|
||||
struct scst_cmd *cmd, *tc;
|
||||
spin_lock_irq(&scst_tm_dbg_lock);
|
||||
list_for_each_entry_safe_reverse(cmd, tc,
|
||||
&tm_dbg_delayed_cmd_list, cmd_list_entry) {
|
||||
TRACE_MGMT_DBG("%s: Releasing timed cmd %p "
|
||||
"(tag %d), delayed_cmds_count=%d", __func__,
|
||||
cmd, cmd->tag, tm_dbg_delayed_cmds_count);
|
||||
list_move(&cmd->cmd_list_entry, &scst_active_cmd_list);
|
||||
TRACE_MGMT_DBG("Releasing timed cmd %p (tag %d), "
|
||||
"delayed_cmds_count=%d", cmd, cmd->tag,
|
||||
tm_dbg_delayed_cmds_count);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
list_move(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
}
|
||||
tm_dbg_release = 0;
|
||||
tm_dbg_flags.tm_dbg_release = 0;
|
||||
spin_unlock_irq(&scst_tm_dbg_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called under scst_tm_dbg_lock */
|
||||
static void tm_dbg_change_state(void)
|
||||
{
|
||||
tm_dbg_blocked = 0;
|
||||
tm_dbg_flags.tm_dbg_blocked = 0;
|
||||
if (--tm_dbg_on_state_passes == 0) {
|
||||
switch(tm_dbg_state) {
|
||||
case TM_DBG_STATE_ABORT:
|
||||
@@ -2375,7 +2417,7 @@ static void tm_dbg_change_state(void)
|
||||
"tm_dbg_state to RESET");
|
||||
tm_dbg_state =
|
||||
TM_DBG_STATE_RESET;
|
||||
tm_dbg_blocked = 0;
|
||||
tm_dbg_flags.tm_dbg_blocked = 0;
|
||||
break;
|
||||
case TM_DBG_STATE_RESET:
|
||||
case TM_DBG_STATE_OFFLINE:
|
||||
@@ -2402,15 +2444,17 @@ static void tm_dbg_change_state(void)
|
||||
del_timer(&tm_dbg_timer);
|
||||
}
|
||||
|
||||
/* Called under scst_list_lock */
|
||||
/* No locks */
|
||||
int tm_dbg_check_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (cmd->tm_dbg_immut)
|
||||
goto out;
|
||||
|
||||
if (cmd->tm_dbg_delayed) {
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
TRACE_MGMT_DBG("Processing delayed cmd %p (tag %d), "
|
||||
"delayed_cmds_count=%d", cmd, cmd->tag,
|
||||
tm_dbg_delayed_cmds_count);
|
||||
@@ -2420,25 +2464,31 @@ int tm_dbg_check_cmd(struct scst_cmd *cmd)
|
||||
if ((tm_dbg_delayed_cmds_count == 0) &&
|
||||
(tm_dbg_state == TM_DBG_STATE_ABORT))
|
||||
tm_dbg_change_state();
|
||||
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
} else if (cmd->tgt_dev && test_bit(SCST_TGT_DEV_UNDER_TM_DBG,
|
||||
&cmd->tgt_dev->tgt_dev_flags)) {
|
||||
/* Delay 50th command */
|
||||
if (tm_dbg_blocked || (++tm_dbg_passed_cmds_count % 50) == 0) {
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
if (tm_dbg_flags.tm_dbg_blocked ||
|
||||
(++tm_dbg_passed_cmds_count % 50) == 0) {
|
||||
tm_dbg_delay_cmd(cmd);
|
||||
res = 1;
|
||||
} else
|
||||
cmd->tm_dbg_immut = 1;
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
}
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Called under scst_list_lock */
|
||||
/* No locks */
|
||||
void tm_dbg_release_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
struct scst_cmd *c;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
list_for_each_entry(c, &tm_dbg_delayed_cmd_list,
|
||||
cmd_list_entry) {
|
||||
if (c == cmd) {
|
||||
@@ -2446,30 +2496,38 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
|
||||
"delayed cmd %p (tag=%d), moving it to "
|
||||
"active cmd list (delayed_cmds_count=%d)",
|
||||
c, c->tag, tm_dbg_delayed_cmds_count);
|
||||
list_move(&c->cmd_list_entry, &scst_active_cmd_list);
|
||||
wake_up_all(&scst_list_waitQ);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
list_move(&c->cmd_list_entry,
|
||||
&c->cmd_lists->active_cmd_list);
|
||||
wake_up(&c->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
}
|
||||
|
||||
/* Called under scst_list_lock */
|
||||
void tm_dbg_task_mgmt(const char *fn)
|
||||
/* No locks */
|
||||
void tm_dbg_task_mgmt(const char *fn, int force)
|
||||
{
|
||||
if (tm_dbg_state != TM_DBG_STATE_OFFLINE) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
if ((tm_dbg_state != TM_DBG_STATE_OFFLINE) || force) {
|
||||
TRACE_MGMT_DBG("%s: freeing %d delayed cmds", fn,
|
||||
tm_dbg_delayed_cmds_count);
|
||||
tm_dbg_change_state();
|
||||
tm_dbg_release = 1;
|
||||
tm_dbg_flags.tm_dbg_release = 1;
|
||||
smp_mb();
|
||||
wake_up_all(&scst_list_waitQ);
|
||||
wake_up_all(tm_dbg_p_cmd_list_waitQ);
|
||||
} else {
|
||||
TRACE_MGMT_DBG("%s: while OFFLINE state, doing nothing", fn);
|
||||
}
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
}
|
||||
|
||||
int tm_dbg_is_release(void)
|
||||
{
|
||||
return tm_dbg_release;
|
||||
return tm_dbg_flags.tm_dbg_release;
|
||||
}
|
||||
#endif /* DEBUG_TM */
|
||||
|
||||
@@ -70,8 +70,15 @@ extern unsigned long scst_trace_flag;
|
||||
** Bits for scst_flags
|
||||
**/
|
||||
|
||||
/* Set if new commands initialization should be suspended for a while */
|
||||
#define SCST_FLAG_SUSPENDED 0
|
||||
/*
|
||||
* Set if new commands initialization is being suspended for a while.
|
||||
* Used to let TM commands execute while preparing the suspend, since
|
||||
* RESET or ABORT could be necessary to free SCSI commands.
|
||||
*/
|
||||
#define SCST_FLAG_SUSPENDING 0
|
||||
|
||||
/* Set if new commands initialization is suspended for a while */
|
||||
#define SCST_FLAG_SUSPENDED 1
|
||||
|
||||
/* Set if a TM command is being performed */
|
||||
#define SCST_FLAG_TM_ACTIVE 2
|
||||
@@ -129,13 +136,13 @@ extern struct kmem_cache *scst_tgtd_cachep;
|
||||
#define SCST_ACG_DEV_CACHE_STRING "scst_acg_dev"
|
||||
extern struct kmem_cache *scst_acgd_cachep;
|
||||
|
||||
extern spinlock_t scst_main_lock;
|
||||
|
||||
extern struct scst_sgv_pools scst_sgv;
|
||||
|
||||
extern unsigned long scst_flags;
|
||||
extern struct semaphore scst_mutex;
|
||||
extern atomic_t scst_cmd_count;
|
||||
extern spinlock_t scst_list_lock;
|
||||
extern struct list_head scst_dev_wait_sess_list; /* protected by scst_list_lock */
|
||||
extern struct list_head scst_template_list; /* protected by scst_mutex */
|
||||
extern struct list_head scst_dev_list; /* protected by scst_mutex */
|
||||
extern struct list_head scst_dev_type_list; /* protected by scst_mutex */
|
||||
@@ -144,10 +151,12 @@ extern wait_queue_head_t scst_dev_cmd_waitQ;
|
||||
extern struct list_head scst_acg_list;
|
||||
extern struct scst_acg *scst_default_acg;
|
||||
|
||||
/* The following lists protected by scst_list_lock */
|
||||
extern struct list_head scst_active_cmd_list;
|
||||
extern spinlock_t scst_init_lock;
|
||||
extern struct list_head scst_init_cmd_list;
|
||||
extern struct list_head scst_cmd_list;
|
||||
extern wait_queue_head_t scst_init_cmd_list_waitQ;
|
||||
extern unsigned int scst_init_poll_cnt;
|
||||
|
||||
extern struct scst_cmd_lists scst_main_cmd_lists;
|
||||
|
||||
extern spinlock_t scst_cmd_mem_lock;
|
||||
extern unsigned long scst_max_cmd_mem, scst_cur_max_cmd_mem, scst_cur_cmd_mem;
|
||||
@@ -157,16 +166,21 @@ extern struct work_struct scst_cmd_mem_work;
|
||||
extern struct delayed_work scst_cmd_mem_work;
|
||||
#endif
|
||||
|
||||
/* The following lists protected by scst_list_lock as well */
|
||||
extern struct list_head scst_mgmt_cmd_list;
|
||||
extern spinlock_t scst_mcmd_lock;
|
||||
/* The following lists protected by scst_mcmd_lock */
|
||||
extern struct list_head scst_active_mgmt_cmd_list;
|
||||
extern struct list_head scst_delayed_mgmt_cmd_list;
|
||||
|
||||
extern struct tasklet_struct scst_tasklets[NR_CPUS];
|
||||
extern wait_queue_head_t scst_list_waitQ;
|
||||
|
||||
extern wait_queue_head_t scst_mgmt_cmd_list_waitQ;
|
||||
|
||||
struct scst_tasklet
|
||||
{
|
||||
spinlock_t tasklet_lock;
|
||||
struct list_head tasklet_cmd_list;
|
||||
struct tasklet_struct tasklet;
|
||||
};
|
||||
extern struct scst_tasklet scst_tasklets[NR_CPUS];
|
||||
|
||||
extern wait_queue_head_t scst_mgmt_waitQ;
|
||||
extern spinlock_t scst_mgmt_lock;
|
||||
extern struct list_head scst_sess_mgmt_list;
|
||||
@@ -180,6 +194,7 @@ struct scst_threads_info_t {
|
||||
struct semaphore cmd_threads_mutex;
|
||||
u32 nr_cmd_threads;
|
||||
struct list_head cmd_threads_list;
|
||||
struct task_struct *init_cmd_thread;
|
||||
struct task_struct *mgmt_thread;
|
||||
struct task_struct *mgmt_cmd_thread;
|
||||
};
|
||||
@@ -223,10 +238,11 @@ static inline int __scst_inc_expected_sn(struct scst_tgt_dev *tgt_dev)
|
||||
}
|
||||
|
||||
void scst_inc_expected_sn_unblock(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_cmd *cmd_sn, int locked);
|
||||
struct scst_cmd *cmd_sn);
|
||||
|
||||
int scst_cmd_thread(void *arg);
|
||||
void scst_cmd_tasklet(long p);
|
||||
int scst_init_cmd_thread(void *arg);
|
||||
int scst_mgmt_cmd_thread(void *arg);
|
||||
int scst_mgmt_thread(void *arg);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
|
||||
@@ -276,7 +292,7 @@ static inline void scst_destroy_cmd(struct scst_cmd *cmd)
|
||||
|
||||
void scst_proccess_redirect_cmd(struct scst_cmd *cmd, int context,
|
||||
int check_retries);
|
||||
void scst_check_retries(struct scst_tgt *tgt, int processible_env);
|
||||
void scst_check_retries(struct scst_tgt *tgt);
|
||||
void scst_tgt_retry_timer_fn(unsigned long arg);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
|
||||
@@ -324,7 +340,8 @@ struct scst_cmd *__scst_find_cmd_by_tag(struct scst_session *sess,
|
||||
uint32_t tag);
|
||||
|
||||
struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(int gfp_mask);
|
||||
void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd, int del);
|
||||
void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd);
|
||||
void scst_complete_cmd_mgmt(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd);
|
||||
|
||||
/* /proc support */
|
||||
int scst_proc_init_module(void);
|
||||
@@ -438,21 +455,24 @@ static inline void scst_dec_on_dev_cmd(struct scst_cmd *cmd)
|
||||
wake_up_all(&cmd->dev->on_dev_waitQ);
|
||||
}
|
||||
|
||||
static inline void scst_inc_cmd_count(void)
|
||||
static inline void __scst_get(int barrier)
|
||||
{
|
||||
atomic_inc(&scst_cmd_count);
|
||||
/* It's needed to be before test_bit(SCST_FLAG_SUSPENDED) */
|
||||
smp_mb__after_atomic_inc();
|
||||
TRACE_DBG("Incrementing scst_cmd_count(%d)",
|
||||
atomic_read(&scst_cmd_count));
|
||||
atomic_read(&scst_cmd_count));
|
||||
|
||||
if (barrier)
|
||||
smp_mb__after_atomic_inc();
|
||||
}
|
||||
|
||||
static inline void scst_dec_cmd_count(void)
|
||||
static inline void __scst_put(void)
|
||||
{
|
||||
int f;
|
||||
f = atomic_dec_and_test(&scst_cmd_count);
|
||||
if (f && unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags)))
|
||||
if (f && unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) {
|
||||
TRACE_MGMT_DBG("%s", "Waking up scst_dev_cmd_waitQ");
|
||||
wake_up_all(&scst_dev_cmd_waitQ);
|
||||
}
|
||||
TRACE_DBG("Decrementing scst_cmd_count(%d)",
|
||||
atomic_read(&scst_cmd_count));
|
||||
}
|
||||
@@ -470,8 +490,16 @@ static inline void scst_sess_put(struct scst_session *sess)
|
||||
scst_sched_session_free(sess);
|
||||
}
|
||||
|
||||
void __scst_suspend_activity(void);
|
||||
void __scst_resume_activity(void);
|
||||
static inline void scst_cmd_get(struct scst_cmd *cmd)
|
||||
{
|
||||
atomic_inc(&cmd->cmd_ref);
|
||||
}
|
||||
|
||||
static inline void scst_cmd_put(struct scst_cmd *cmd)
|
||||
{
|
||||
if (atomic_dec_and_test(&cmd->cmd_ref))
|
||||
scst_free_cmd(cmd);
|
||||
}
|
||||
|
||||
extern void scst_throttle_cmd(struct scst_cmd *cmd);
|
||||
extern void scst_unthrottle_cmd(struct scst_cmd *cmd);
|
||||
@@ -504,7 +532,7 @@ extern void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev);
|
||||
extern void tm_dbg_check_released_cmds(void);
|
||||
extern int tm_dbg_check_cmd(struct scst_cmd *cmd);
|
||||
extern void tm_dbg_release_cmd(struct scst_cmd *cmd);
|
||||
extern void tm_dbg_task_mgmt(const char *fn);
|
||||
extern void tm_dbg_task_mgmt(const char *fn, int force);
|
||||
extern int tm_dbg_is_release(void);
|
||||
#else
|
||||
static inline void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
@@ -516,7 +544,7 @@ static inline int tm_dbg_check_cmd(struct scst_cmd *cmd)
|
||||
return 0;
|
||||
}
|
||||
static inline void tm_dbg_release_cmd(struct scst_cmd *cmd) {}
|
||||
static inline void tm_dbg_task_mgmt(const char *fn) {}
|
||||
static inline void tm_dbg_task_mgmt(const char *fn, int force) {}
|
||||
static inline int tm_dbg_is_release(void)
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -474,7 +474,7 @@ static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
static int scst_proc_group_add(const char *p)
|
||||
{
|
||||
int res = 0, len = strlen(p) + 1;
|
||||
@@ -515,7 +515,7 @@ out_nomem:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc)
|
||||
{
|
||||
const char *name;
|
||||
@@ -1136,9 +1136,11 @@ static int scst_proc_scsi_tgt_gen_write(struct file *file, const char __user *bu
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
scst_suspend_activity();
|
||||
|
||||
if (down_interruptible(&scst_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out_free;
|
||||
goto out_free_resume;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
@@ -1188,14 +1190,18 @@ static int scst_proc_scsi_tgt_gen_write(struct file *file, const char __user *bu
|
||||
out_up_free:
|
||||
up(&scst_mutex);
|
||||
|
||||
out_free_resume:
|
||||
scst_resume_activity();
|
||||
|
||||
out_free:
|
||||
free_page((unsigned long)buffer);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Called under scst_mutex */
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
static int scst_proc_assign_handler(char *buf)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -1354,9 +1360,11 @@ static int scst_proc_groups_devices_write(struct file *file, const char __user *
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
scst_suspend_activity();
|
||||
|
||||
if (down_interruptible(&scst_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out_free;
|
||||
goto out_free_resume;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
@@ -1476,8 +1484,12 @@ static int scst_proc_groups_devices_write(struct file *file, const char __user *
|
||||
out_free_up:
|
||||
up(&scst_mutex);
|
||||
|
||||
out_free_resume:
|
||||
scst_resume_activity();
|
||||
|
||||
out_free:
|
||||
free_page((unsigned long)buffer);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
@@ -1674,12 +1686,12 @@ static int scst_sessions_info_show(struct seq_file *seq, void *v)
|
||||
goto out;
|
||||
}
|
||||
|
||||
seq_printf(seq, "%-20s%-35s%-20s%-15s\n", "Target name", "Initiator name",
|
||||
seq_printf(seq, "%-20s%-35s%-35s%-15s\n", "Target name", "Initiator name",
|
||||
"Group name", "Command Count");
|
||||
|
||||
list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
|
||||
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
|
||||
seq_printf(seq, "%-20s%-35s%-20s%-15d\n",
|
||||
seq_printf(seq, "%-20s%-35s%-35s%-15d\n",
|
||||
sess->tgt->tgtt->name,
|
||||
sess->initiator_name,
|
||||
acg->acg_name,
|
||||
|
||||
1110
scst/src/scst_targ.c
1110
scst/src/scst_targ.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user