TM handling improvements

TM actions should be done only after all affected commands done to avoid
possibility that any of them be executed with newly set parameters.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4217 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2012-04-19 17:46:36 +00:00
parent eb95049061
commit 64699a540a
9 changed files with 301 additions and 163 deletions

View File

@@ -1084,11 +1084,12 @@ where:
</itemize>
<sect1> SCST_USER_TASK_MGMT
<sect1> SCST_USER_TASK_MGMT_RECEIVED
<p>
SCST_USER_TASK_MGMT subcommand returns a task management functions.
Payload contains struct scst_user_tm, which is defined as the following:
SCST_USER_TASK_MGMT_RECEIVED subcommand notifies that a task management
function has been received. Payload contains struct scst_user_tm, which
is defined as the following:
<verb>
struct scst_user_tm
@@ -1118,12 +1119,8 @@ where:
<item> <bf/cmd_sn_set/ - specifies if cmd_sn is valid
</itemize>
After TM function is completed, the user space device handler shall
reply using "result" field of the corresponding reply command. It isn't
necessary to wait for aborted command(s) finished, the result of TM
function shall be returned immediately. SCST core will take care that
the reply to the TM function isn't sent before all affection SCSI
commands finished.
On this notification dev handler should do the best to ensure that all
aborted by this TM command SCSI commands complete ASAP.
Possible values of <it/fn/ field:
@@ -1147,6 +1144,23 @@ Possible values of <it/fn/ field:
<item> <bf/SCST_ABORT_ALL_TASKS/ - all tasks shall be aborted
</itemize>
The "result" field of the corresponding reply command is ignored for
this subcommand.
<sect1> SCST_USER_TASK_MGMT_DONE
<p>
SCST_USER_TASK_MGMT_DONE subcommand notifies that all aborted by task
management function commands have finished, so the dev handler can
perform actual actions required by this TM command. For instance, reset
all MODE PAGES variables to default values.
Payload contains struct scst_user_tm, which was defined above.
After the TM function is completed, the device handler shall reply using
"result" field of the corresponding reply command.
Possible return values are:
<itemize>

View File

@@ -447,13 +447,6 @@ enum scst_exec_context {
/* The cmd should be sent to SCSI mid-level */
#define SCST_EXEC_NOT_COMPLETED 1
/*************************************************************
** Additional return code for dev handler's task_mgmt_fn()
*************************************************************/
/* Regular standard actions for the command should be done */
#define SCST_DEV_TM_NOT_COMPLETED 1
/*************************************************************
** Session initialization phases
*************************************************************/
@@ -1261,14 +1254,7 @@ struct scst_dev_type {
void (*on_free_cmd) (struct scst_cmd *cmd);
/*
* Called to execute a task management command.
* Returns:
* - SCST_MGMT_STATUS_SUCCESS - the command is done with success,
* no further actions required
* - The SCST_MGMT_STATUS_* error code if the command is failed and
* no further actions required
* - SCST_DEV_TM_NOT_COMPLETED - regular standard actions for the
* command should be done
* Called to notify dev handler that a task management command received
*
* Can be called under many internal SCST locks, including under
* disabled IRQs, so dev handler should be careful with locking and,
@@ -1280,7 +1266,25 @@ struct scst_dev_type {
*
* OPTIONAL
*/
int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd,
void (*task_mgmt_fn_received) (struct scst_mgmt_cmd *mgmt_cmd,
struct scst_tgt_dev *tgt_dev);
/*
* Called to execute a task management command. On any problem, error
* code (one of SCST_MGMT_STATUS_* codes) should be set using function
* scst_mgmt_cmd_set_status().
*
* Can be called under many internal SCST locks, including under
* disabled IRQs, so dev handler should be careful with locking and,
* if necessary, pass processing somewhere outside (in a work, e.g.)
*
* But at the moment it's called under disabled IRQs only for
* SCST_ABORT_TASK, however dev handler using it should add a BUG_ON
* trap to catch if it's changed in future.
*
* OPTIONAL
*/
void (*task_mgmt_fn_done) (struct scst_mgmt_cmd *mgmt_cmd,
struct scst_tgt_dev *tgt_dev);
/*
@@ -1928,14 +1932,6 @@ struct scst_cmd {
*/
unsigned int finished:1;
#ifdef CONFIG_SCST_DEBUG_TM
/* Set if the cmd was delayed by task management debugging code */
unsigned int tm_dbg_delayed:1;
/* Set if the cmd must be ignored by task management debugging code */
unsigned int tm_dbg_immut:1;
#endif
/**************************************************************/
/* cmd's async flags */
@@ -2111,13 +2107,22 @@ struct scst_cmd {
#ifdef CONFIG_SCST_MEASURE_LATENCY
/*
* Must be the last to allow to work with drivers who don't know
* about this config time option.
* about this config time option!
*/
uint64_t start, curr_start, parse_time, alloc_buf_time;
uint64_t restart_waiting_time, rdy_to_xfer_time;
uint64_t pre_exec_time, exec_time, dev_done_time;
uint64_t xmit_time, tgt_on_free_time, dev_on_free_time;
#endif
/* Must be the last for the same reason as SCST_MEASURE_LATENCY! */
#ifdef CONFIG_SCST_DEBUG_TM
/* Set if the cmd was delayed by task management debugging code */
unsigned int tm_dbg_delayed:1;
/* Set if the cmd must be ignored by task management debugging code */
unsigned int tm_dbg_immut:1;
#endif
};
/*
@@ -2172,6 +2177,8 @@ struct scst_mgmt_cmd {
unsigned int needs_unblocking:1;
unsigned int lun_set:1; /* set, if lun field is valid */
unsigned int cmd_sn_set:1; /* set, if cmd_sn field is valid */
/* Set if dev handler's task_mgmt_fn_received was called */
unsigned int task_mgmt_fn_received_called:1;
/*
* Number of commands to finish before sending response,
@@ -2197,7 +2204,7 @@ struct scst_mgmt_cmd {
/* corresponding cmd (to be aborted, found by tag) */
struct scst_cmd *cmd_to_abort;
/* corresponding device for this mgmt cmd (found by lun) */
/* corresponding device for this mgmt cmd (found by lun or by tag) */
struct scst_tgt_dev *mcmd_tgt_dev;
/* completion status, one of the SCST_MGMT_STATUS_* constants */
@@ -3533,8 +3540,17 @@ static inline int scst_mgmt_cmd_get_fn(struct scst_mgmt_cmd *mcmd)
return mcmd->fn;
}
static inline void scst_mgmt_cmd_set_status(struct scst_mgmt_cmd *mcmd,
int status)
{
/* Don't replace existing, i.e. the first, not success status */
if ((mcmd->status == SCST_MGMT_STATUS_SUCCESS) &&
(status != SCST_MGMT_STATUS_RECEIVED_STAGE_COMPLETED))
mcmd->status = status;
}
/*
* Called by dev handler's task_mgmt_fn() to notify SCST core that mcmd
* Called by dev handler's task_mgmt_fn_*() to notify SCST core that mcmd
* is going to complete asynchronously.
*/
void scst_prepare_async_mcmd(struct scst_mgmt_cmd *mcmd);

View File

@@ -151,6 +151,9 @@
#define SCST_MGMT_STATUS_REJECTED -255
#define SCST_MGMT_STATUS_FAILED -129
/* Extra status meaning that the received stage completed, not done */
#define SCST_MGMT_STATUS_RECEIVED_STAGE_COMPLETED 200
/*************************************************************
** SCSI LUN addressing methods. See also SAM-2 and the
** section about eight byte LUNs.

View File

@@ -70,7 +70,8 @@
#define UCMD_STATE_ON_FREEING 4
#define UCMD_STATE_ON_FREE_SKIPPED 5
#define UCMD_STATE_ON_CACHE_FREEING 6
#define UCMD_STATE_TM_EXECING 7
#define UCMD_STATE_TM_RECEIVED_EXECING 7
#define UCMD_STATE_TM_DONE_EXECING 8
#define UCMD_STATE_ATTACH_SESS 0x20
#define UCMD_STATE_DETACH_SESS 0x21
@@ -318,7 +319,9 @@ union scst_user_prealloc_buffer {
#define SCST_USER_ON_CACHED_MEM_FREE \
_IOR('s', UCMD_STATE_ON_CACHE_FREEING, \
struct scst_user_on_cached_mem_free)
#define SCST_USER_TASK_MGMT \
_IOWR('s', UCMD_STATE_TM_EXECING, struct scst_user_tm)
#define SCST_USER_TASK_MGMT_RECEIVED \
_IOWR('s', UCMD_STATE_TM_RECEIVED_EXECING, struct scst_user_tm)
#define SCST_USER_TASK_MGMT_DONE \
_IOWR('s', UCMD_STATE_TM_DONE_EXECING, struct scst_user_tm)
#endif /* __SCST_USER_H */

View File

@@ -155,20 +155,8 @@ struct scst_user_cmd {
int result;
};
static struct scst_user_cmd *dev_user_alloc_ucmd(struct scst_user_dev *dev,
gfp_t gfp_mask);
static void dev_user_free_ucmd(struct scst_user_cmd *ucmd);
static int dev_user_parse(struct scst_cmd *cmd);
static int dev_user_alloc_data_buf(struct scst_cmd *cmd);
static int dev_user_exec(struct scst_cmd *cmd);
static void dev_user_on_free_cmd(struct scst_cmd *cmd);
static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev);
static int dev_user_disk_done(struct scst_cmd *cmd);
static int dev_user_tape_done(struct scst_cmd *cmd);
static struct page *dev_user_alloc_pages(struct scatterlist *sg,
gfp_t gfp_mask, void *priv);
static void dev_user_free_sg_entries(struct scatterlist *sg, int sg_count,
@@ -1071,7 +1059,8 @@ static int dev_user_tape_done(struct scst_cmd *cmd)
static inline bool dev_user_mgmt_ucmd(struct scst_user_cmd *ucmd)
{
return (ucmd->state == UCMD_STATE_TM_EXECING) ||
return (ucmd->state == UCMD_STATE_TM_RECEIVED_EXECING) ||
(ucmd->state == UCMD_STATE_TM_DONE_EXECING) ||
(ucmd->state == UCMD_STATE_ATTACH_SESS) ||
(ucmd->state == UCMD_STATE_DETACH_SESS);
}
@@ -1623,8 +1612,12 @@ unlock_process:
res = dev_user_process_reply_on_cache_free(ucmd);
break;
case UCMD_STATE_TM_EXECING:
res = dev_user_process_reply_tm_exec(ucmd, reply->result);
case UCMD_STATE_TM_RECEIVED_EXECING:
case UCMD_STATE_TM_DONE_EXECING:
res = dev_user_process_reply_tm_exec(ucmd,
(state == UCMD_STATE_TM_RECEIVED_EXECING) ?
SCST_MGMT_STATUS_RECEIVED_STAGE_COMPLETED :
reply->result);
break;
case UCMD_STATE_ATTACH_SESS:
@@ -2272,7 +2265,8 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
case UCMD_STATE_ON_FREEING:
case UCMD_STATE_ON_CACHE_FREEING:
case UCMD_STATE_TM_EXECING:
case UCMD_STATE_TM_RECEIVED_EXECING:
case UCMD_STATE_TM_DONE_EXECING:
case UCMD_STATE_ATTACH_SESS:
case UCMD_STATE_DETACH_SESS:
if (flags != NULL)
@@ -2290,9 +2284,12 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
dev_user_process_reply_on_cache_free(ucmd);
break;
case UCMD_STATE_TM_EXECING:
case UCMD_STATE_TM_RECEIVED_EXECING:
case UCMD_STATE_TM_DONE_EXECING:
dev_user_process_reply_tm_exec(ucmd,
SCST_MGMT_STATUS_FAILED);
(state == UCMD_STATE_TM_RECEIVED_EXECING) ?
SCST_MGMT_STATUS_RECEIVED_STAGE_COMPLETED :
SCST_MGMT_STATUS_FAILED);
break;
case UCMD_STATE_ATTACH_SESS:
@@ -2430,8 +2427,8 @@ again:
}
/* Can be called under some spinlock and IRQs off */
static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
static void __dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev, bool done)
{
struct scst_user_cmd *ucmd;
struct scst_user_dev *dev = tgt_dev->dev->dh_priv;
@@ -2477,7 +2474,8 @@ static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
* stuck commands would affect only related devices.
*/
dev_user_abort_ready_commands(dev);
if (!done)
dev_user_abort_ready_commands(dev);
/* We can't afford missing TM command due to memory shortage */
ucmd = dev_user_alloc_ucmd(dev, GFP_ATOMIC|__GFP_NOFAIL);
@@ -2491,7 +2489,10 @@ static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
offsetof(struct scst_user_get_cmd, tm_cmd) +
sizeof(ucmd->user_cmd.tm_cmd);
ucmd->user_cmd.cmd_h = ucmd->h;
ucmd->user_cmd.subcode = SCST_USER_TASK_MGMT;
if (done)
ucmd->user_cmd.subcode = SCST_USER_TASK_MGMT_DONE;
else
ucmd->user_cmd.subcode = SCST_USER_TASK_MGMT_RECEIVED;
ucmd->user_cmd.tm_cmd.sess_h = (unsigned long)tgt_dev;
ucmd->user_cmd.tm_cmd.fn = mcmd->fn;
ucmd->user_cmd.tm_cmd.cmd_sn = mcmd->cmd_sn;
@@ -2509,7 +2510,10 @@ static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
ucmd->user_cmd.tm_cmd.cmd_h_to_abort, mcmd);
ucmd->mcmd = mcmd;
ucmd->state = UCMD_STATE_TM_EXECING;
if (done)
ucmd->state = UCMD_STATE_TM_DONE_EXECING;
else
ucmd->state = UCMD_STATE_TM_RECEIVED_EXECING;
scst_prepare_async_mcmd(mcmd);
@@ -2517,7 +2521,25 @@ static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
out:
TRACE_EXIT();
return SCST_DEV_TM_NOT_COMPLETED;
return;
}
static void dev_user_task_mgmt_fn_received(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
TRACE_ENTRY();
__dev_user_task_mgmt_fn(mcmd, tgt_dev, false);
TRACE_EXIT();
return;
}
static void dev_user_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
TRACE_ENTRY();
__dev_user_task_mgmt_fn(mcmd, tgt_dev, true);
TRACE_EXIT();
return;
}
static int dev_user_attach(struct scst_device *sdev)
@@ -2956,7 +2978,8 @@ static int dev_user_register_dev(struct file *file,
dev->devtype.detach_tgt = dev_user_detach_tgt;
dev->devtype.exec = dev_user_exec;
dev->devtype.on_free_cmd = dev_user_on_free_cmd;
dev->devtype.task_mgmt_fn = dev_user_task_mgmt_fn;
dev->devtype.task_mgmt_fn_received = dev_user_task_mgmt_fn_received;
dev->devtype.task_mgmt_fn_done = dev_user_task_mgmt_fn_done;
if (dev_desc->enable_pr_cmds_notifications)
dev->devtype.pr_cmds_notifications = 1;

View File

@@ -277,7 +277,7 @@ static ssize_t vdisk_del_device(const char *device_name);
static ssize_t vcdrom_add_device(const char *device_name, char *params);
static ssize_t vcdrom_del_device(const char *device_name);
#endif
static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev);
static uint64_t vdisk_gen_dev_id_num(const char *virt_dev_name);
@@ -445,7 +445,7 @@ static struct scst_dev_type vdisk_file_devtype = {
.alloc_data_buf = fileio_alloc_data_buf,
.exec = vdisk_exec,
.on_free_cmd = fileio_on_free_cmd,
.task_mgmt_fn = vdisk_task_mgmt_fn,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.devt_priv = (void *)fileio_ops,
#ifdef CONFIG_SCST_PROC
.read_proc = vdisk_read_proc,
@@ -485,7 +485,7 @@ static struct scst_dev_type vdisk_blk_devtype = {
.detach_tgt = vdisk_detach_tgt,
.parse = non_fileio_parse,
.exec = non_fileio_exec,
.task_mgmt_fn = vdisk_task_mgmt_fn,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.devt_priv = (void *)blockio_ops,
#ifndef CONFIG_SCST_PROC
.add_device = vdisk_add_blockio_device,
@@ -520,7 +520,7 @@ static struct scst_dev_type vdisk_null_devtype = {
.detach_tgt = vdisk_detach_tgt,
.parse = non_fileio_parse,
.exec = non_fileio_exec,
.task_mgmt_fn = vdisk_task_mgmt_fn,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.devt_priv = (void *)nullio_ops,
#ifndef CONFIG_SCST_PROC
.add_device = vdisk_add_nullio_device,
@@ -553,7 +553,7 @@ static struct scst_dev_type vcdrom_devtype = {
.alloc_data_buf = fileio_alloc_data_buf,
.exec = vcdrom_exec,
.on_free_cmd = fileio_on_free_cmd,
.task_mgmt_fn = vdisk_task_mgmt_fn,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
#ifdef CONFIG_SCST_PROC
.read_proc = vcdrom_read_proc,
.write_proc = vcdrom_write_proc,
@@ -3963,7 +3963,7 @@ static enum compl_status_e nullio_exec_write_verify(struct vdisk_cmd_params *p)
return CMD_SUCCEEDED;
}
static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
TRACE_ENTRY();
@@ -3994,7 +3994,7 @@ static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
}
TRACE_EXIT();
return SCST_DEV_TM_NOT_COMPLETED;
return;
}
static void vdisk_report_registering(const struct scst_vdisk_dev *virt_dev)

View File

@@ -4404,6 +4404,8 @@ struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(gfp_t gfp_mask)
}
memset(mcmd, 0, sizeof(*mcmd));
mcmd->status = SCST_MGMT_STATUS_SUCCESS;
out:
TRACE_EXIT();
return mcmd;
@@ -7064,7 +7066,7 @@ static const int tm_dbg_on_state_num_passes[] = { 5, 1, 0x7ffffff };
static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev)
{
if (tgt_dev->lun == 6) {
if (tgt_dev->lun == 15) {
unsigned long flags;
if (tm_dbg_tgt_dev != NULL)
@@ -7101,8 +7103,6 @@ static void tm_dbg_timer_fn(unsigned long arg)
{
TRACE_MGMT_DBG("%s", "delayed cmd timer expired");
tm_dbg_flags.tm_dbg_release = 1;
/* Used to make sure that all woken up threads see the new value */
smp_wmb();
wake_up_all(&tm_dbg_tgt_dev->active_cmd_threads->cmd_list_waitQ);
return;
}
@@ -7175,8 +7175,8 @@ void tm_dbg_check_released_cmds(void)
}
}
/* Called under scst_tm_dbg_lock */
static void tm_dbg_change_state(void)
/* Called under scst_tm_dbg_lock, but can drop it inside, then reget */
static void tm_dbg_change_state(unsigned long *flags)
{
tm_dbg_flags.tm_dbg_blocked = 0;
if (--tm_dbg_on_state_passes == 0) {
@@ -7207,7 +7207,9 @@ static void tm_dbg_change_state(void)
}
TRACE_MGMT_DBG("%s", "Deleting timer");
spin_unlock_irqrestore(&scst_tm_dbg_lock, *flags);
del_timer_sync(&tm_dbg_timer);
spin_lock_irqsave(&scst_tm_dbg_lock, *flags);
return;
}
@@ -7230,13 +7232,13 @@ int tm_dbg_check_cmd(struct scst_cmd *cmd)
tm_dbg_delayed_cmds_count--;
if ((tm_dbg_delayed_cmds_count == 0) &&
(tm_dbg_state == TM_DBG_STATE_ABORT))
tm_dbg_change_state();
tm_dbg_change_state(&flags);
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
} else if (cmd->tgt_dev && (tm_dbg_tgt_dev == cmd->tgt_dev)) {
/* Delay 50th command */
/* Delay 5000th command */
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
if (tm_dbg_flags.tm_dbg_blocked ||
(++tm_dbg_passed_cmds_count % 50) == 0) {
(++tm_dbg_passed_cmds_count % 5000) == 0) {
tm_dbg_delay_cmd(cmd);
res = 1;
} else
@@ -7263,6 +7265,9 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
"active cmd list (delayed_cmds_count=%d)",
c, c->tag, tm_dbg_delayed_cmds_count);
if (!(in_atomic() || in_interrupt() || irqs_disabled()))
msleep(2000);
if (!test_bit(SCST_CMD_ABORTED_OTHER,
&cmd->cmd_flags)) {
/* Test how completed commands handled */
@@ -7303,7 +7308,7 @@ void tm_dbg_task_mgmt(struct scst_device *dev, const char *fn, int force)
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_change_state(&flags);
tm_dbg_flags.tm_dbg_release = 1;
/*
* Used to make sure that all woken up threads see the new

View File

@@ -4565,8 +4565,7 @@ void scst_async_mcmd_completed(struct scst_mgmt_cmd *mcmd, int status)
spin_lock_irqsave(&scst_mcmd_lock, flags);
if (status != SCST_MGMT_STATUS_SUCCESS)
mcmd->status = status;
scst_mgmt_cmd_set_status(mcmd, status);
__scst_dec_finish_wait_count(mcmd, &wake);
@@ -4622,22 +4621,36 @@ static void scst_finish_cmd_mgmt(struct scst_cmd *cmd)
return;
}
static int scst_call_dev_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev, int set_status)
static void scst_call_dev_task_mgmt_fn_received(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
int res = SCST_DEV_TM_NOT_COMPLETED;
struct scst_dev_type *h = tgt_dev->dev->handler;
if (h->task_mgmt_fn) {
TRACE_MGMT_DBG("Calling dev handler %s task_mgmt_fn(fn=%d)",
mcmd->task_mgmt_fn_received_called = 1;
if (h->task_mgmt_fn_received) {
TRACE_MGMT_DBG("Calling dev handler %s task_mgmt_fn_received(fn=%d)",
h->name, mcmd->fn);
res = h->task_mgmt_fn(mcmd, tgt_dev);
TRACE_MGMT_DBG("Dev handler %s task_mgmt_fn() returned %d",
h->name, res);
if (set_status && (res != SCST_DEV_TM_NOT_COMPLETED))
mcmd->status = res;
h->task_mgmt_fn_received(mcmd, tgt_dev);
TRACE_MGMT_DBG("Dev handler %s task_mgmt_fn_received() returned",
h->name);
}
return res;
return;
}
static void scst_call_dev_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
struct scst_dev_type *h = tgt_dev->dev->handler;
if (h->task_mgmt_fn_done) {
TRACE_MGMT_DBG("Calling dev handler %s task_mgmt_fn_done(fn=%d)",
h->name, mcmd->fn);
h->task_mgmt_fn_done(mcmd, tgt_dev);
TRACE_MGMT_DBG("Dev handler %s task_mgmt_fn_done() returned",
h->name);
}
return;
}
static inline int scst_is_strict_mgmt_fn(int mgmt_fn)
@@ -4661,7 +4674,7 @@ static inline int scst_is_strict_mgmt_fn(int mgmt_fn)
* scst_finish_cmd()
*/
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
bool other_ini, bool call_dev_task_mgmt_fn)
bool other_ini, bool call_dev_task_mgmt_fn_received)
{
unsigned long flags;
static DEFINE_SPINLOCK(other_ini_lock);
@@ -4717,8 +4730,9 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
wake_up(&scst_init_cmd_list_waitQ);
}
if (!cmd->finished && call_dev_task_mgmt_fn && (cmd->tgt_dev != NULL))
scst_call_dev_task_mgmt_fn(mcmd, cmd->tgt_dev, 1);
if (!cmd->finished && call_dev_task_mgmt_fn_received &&
(cmd->tgt_dev != NULL))
scst_call_dev_task_mgmt_fn_received(mcmd, cmd->tgt_dev);
spin_lock_irqsave(&scst_mcmd_lock, flags);
if ((mcmd != NULL) && !cmd->finished) {
@@ -4991,7 +5005,7 @@ static int scst_abort_task_set(struct scst_mgmt_cmd *mcmd)
scst_unblock_aborted_cmds(0);
scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev);
res = scst_set_mcmd_next_state(mcmd);
@@ -5103,7 +5117,7 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd)
}
}
scst_call_dev_task_mgmt_fn(mcmd, mcmd->mcmd_tgt_dev, 0);
scst_call_dev_task_mgmt_fn_received(mcmd, mcmd->mcmd_tgt_dev);
res = scst_set_mcmd_next_state(mcmd);
@@ -5124,6 +5138,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
{
struct scst_session *sess = mcmd->sess;
struct scst_cmd *cmd;
struct scst_tgt_dev *tgt_dev;
spin_lock_irq(&sess->sess_list_lock);
cmd = __scst_find_cmd_by_tag(sess, mcmd->tag, true);
@@ -5131,16 +5146,21 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
TRACE_MGMT_DBG("ABORT TASK: command "
"for tag %llu not found",
(long long unsigned int)mcmd->tag);
mcmd->status = SCST_MGMT_STATUS_TASK_NOT_EXIST;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_TASK_NOT_EXIST);
spin_unlock_irq(&sess->sess_list_lock);
res = scst_set_mcmd_next_state(mcmd);
goto out;
}
__scst_cmd_get(cmd);
tgt_dev = cmd->tgt_dev;
if (tgt_dev != NULL)
mcmd->cpu_cmd_counter = scst_get();
spin_unlock_irq(&sess->sess_list_lock);
TRACE_DBG("Cmd to abort %p for tag %llu found",
cmd, (long long unsigned int)mcmd->tag);
TRACE_DBG("Cmd to abort %p for tag %llu found (tgt_dev %p)",
cmd, (long long unsigned int)mcmd->tag, tgt_dev);
mcmd->cmd_to_abort = cmd;
sBUG_ON(mcmd->mcmd_tgt_dev != NULL);
mcmd->mcmd_tgt_dev = tgt_dev;
mcmd->state = SCST_MCMD_STATE_EXEC;
break;
}
@@ -5165,7 +5185,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
else if (rc < 0) {
PRINT_ERROR("Corresponding device for LUN %lld not "
"found", (long long unsigned int)mcmd->lun);
mcmd->status = SCST_MGMT_STATUS_LUN_NOT_EXIST;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_LUN_NOT_EXIST);
res = scst_set_mcmd_next_state(mcmd);
} else
res = rc;
@@ -5187,7 +5207,6 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
struct scst_device *dev;
struct scst_acg *acg = mcmd->sess->acg;
struct scst_acg_dev *acg_dev;
int cont, c;
LIST_HEAD(host_devs);
TRACE_ENTRY();
@@ -5211,24 +5230,15 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
scst_process_reset(dev, mcmd->sess, NULL, mcmd, true);
spin_unlock_bh(&dev->dev_lock);
cont = 0;
c = 0;
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
cont = 1;
if (mcmd->sess == tgt_dev->sess) {
rc = scst_call_dev_task_mgmt_fn(mcmd,
tgt_dev, 0);
if (rc == SCST_DEV_TM_NOT_COMPLETED)
c = 1;
else if ((rc < 0) &&
(mcmd->status == SCST_MGMT_STATUS_SUCCESS))
mcmd->status = rc;
scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev);
break;
}
}
if (cont && !c)
continue;
tm_dbg_task_mgmt(dev, "TARGET RESET", 0);
if (dev->scsi_dev == NULL)
continue;
@@ -5242,8 +5252,6 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
}
if (!found)
list_add_tail(&dev->tm_dev_list_entry, &host_devs);
tm_dbg_task_mgmt(dev, "TARGET RESET", 0);
}
scst_unblock_aborted_cmds(1);
@@ -5272,7 +5280,7 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
* SCSI_TRY_RESET_BUS is also done by
* scsi_reset_provider()
*/
mcmd->status = SCST_MGMT_STATUS_FAILED;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_FAILED);
}
#else
/*
@@ -5315,9 +5323,7 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
scst_process_reset(dev, mcmd->sess, NULL, mcmd, true);
spin_unlock_bh(&dev->dev_lock);
rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 1);
if (rc != SCST_DEV_TM_NOT_COMPLETED)
goto out_tm_dbg;
scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev);
if (dev->scsi_dev != NULL) {
TRACE(TRACE_MGMT, "Resetting host %d bus ",
@@ -5325,7 +5331,7 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
rc = scsi_reset_provider(dev->scsi_dev, SCSI_TRY_RESET_DEVICE);
#if 0
if (rc != SUCCESS && mcmd->status == SCST_MGMT_STATUS_SUCCESS)
mcmd->status = SCST_MGMT_STATUS_FAILED;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_FAILED);
#else
/*
* scsi_reset_provider() returns very weird status, so let's
@@ -5337,7 +5343,6 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
scst_unblock_aborted_cmds(0);
out_tm_dbg:
tm_dbg_task_mgmt(mcmd->mcmd_tgt_dev->dev, "LUN RESET", 0);
res = scst_set_mcmd_next_state(mcmd);
@@ -5391,13 +5396,9 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
struct list_head *head = &sess->sess_tgt_dev_list[i];
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
int rc;
__scst_abort_task_set(mcmd, tgt_dev);
rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
if (rc < 0 && mcmd->status == SCST_MGMT_STATUS_SUCCESS)
mcmd->status = rc;
scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev);
tm_dbg_task_mgmt(tgt_dev->dev, "NEXUS LOSS SESS or "
"ABORT ALL SESS or UNREG SESS",
@@ -5465,17 +5466,11 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, head,
sess_tgt_dev_list_entry) {
int rc;
__scst_abort_task_set(mcmd, tgt_dev);
if (mcmd->sess == tgt_dev->sess) {
rc = scst_call_dev_task_mgmt_fn(
mcmd, tgt_dev, 0);
if ((rc < 0) &&
(mcmd->status == SCST_MGMT_STATUS_SUCCESS))
mcmd->status = rc;
}
if (mcmd->sess == tgt_dev->sess)
scst_call_dev_task_mgmt_fn_received(
mcmd, tgt_dev);
tm_dbg_task_mgmt(tgt_dev->dev, "NEXUS LOSS or "
"ABORT ALL", 0);
@@ -5510,14 +5505,14 @@ static int scst_abort_task(struct scst_mgmt_cmd *mcmd)
(long long unsigned int)mcmd->lun,
(long long unsigned int)cmd->lun,
(long long unsigned int)mcmd->tag);
mcmd->status = SCST_MGMT_STATUS_REJECTED;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_REJECTED);
} else if (mcmd->cmd_sn_set &&
(scst_sn_before(mcmd->cmd_sn, cmd->tgt_sn) ||
(mcmd->cmd_sn == cmd->tgt_sn))) {
PRINT_ERROR("ABORT TASK: SN mismatch: mcmd SN %x, "
"cmd SN %x, cmd tag %llu", mcmd->cmd_sn,
cmd->tgt_sn, (long long unsigned int)mcmd->tag);
mcmd->status = SCST_MGMT_STATUS_REJECTED;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_REJECTED);
} else {
spin_lock_irq(&cmd->sess->sess_list_lock);
scst_abort_cmd(cmd, mcmd, 0, 1);
@@ -5543,8 +5538,6 @@ static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd *mcmd)
TRACE_ENTRY();
mcmd->status = SCST_MGMT_STATUS_SUCCESS;
switch (mcmd->fn) {
case SCST_ABORT_TASK:
res = scst_abort_task(mcmd);
@@ -5589,16 +5582,13 @@ static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd *mcmd)
break;
case SCST_CLEAR_ACA:
if (scst_call_dev_task_mgmt_fn(mcmd, mcmd->mcmd_tgt_dev, 1) ==
SCST_DEV_TM_NOT_COMPLETED) {
mcmd->status = SCST_MGMT_STATUS_FN_NOT_SUPPORTED;
/* Nothing to do (yet) */
}
/* Nothing to do (yet) */
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_FN_NOT_SUPPORTED);
goto out_done;
default:
PRINT_ERROR("Unknown task management function %d", mcmd->fn);
mcmd->status = SCST_MGMT_STATUS_REJECTED;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_REJECTED);
goto out_done;
}
@@ -5629,7 +5619,10 @@ static void scst_call_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
{
int res;
int res, i;
struct scst_session *sess = mcmd->sess;
struct scst_device *dev;
struct scst_tgt_dev *tgt_dev;
TRACE_ENTRY();
@@ -5648,6 +5641,79 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
mutex_unlock(&scst_mutex);
if (!mcmd->task_mgmt_fn_received_called)
goto tgt_done;
switch (mcmd->fn) {
case SCST_ABORT_TASK:
case SCST_ABORT_TASK_SET:
case SCST_CLEAR_TASK_SET:
case SCST_PR_ABORT_ALL:
case SCST_LUN_RESET:
scst_call_dev_task_mgmt_fn_done(mcmd, mcmd->mcmd_tgt_dev);
break;
case SCST_TARGET_RESET:
{
struct scst_acg *acg = sess->acg;
struct scst_acg_dev *acg_dev;
mutex_lock(&scst_mutex);
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
dev = acg_dev->dev;
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
if (mcmd->sess == tgt_dev->sess) {
scst_call_dev_task_mgmt_fn_done(mcmd, tgt_dev);
break;
}
}
}
mutex_unlock(&scst_mutex);
break;
}
case SCST_ABORT_ALL_TASKS_SESS:
case SCST_NEXUS_LOSS_SESS:
case SCST_UNREG_SESS_TM:
mutex_lock(&scst_mutex);
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
struct list_head *head = &sess->sess_tgt_dev_list[i];
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
scst_call_dev_task_mgmt_fn_done(mcmd, tgt_dev);
}
}
mutex_unlock(&scst_mutex);
break;
case SCST_ABORT_ALL_TASKS:
case SCST_NEXUS_LOSS:
{
struct scst_session *s;
struct scst_tgt *tgt = sess->tgt;
mutex_lock(&scst_mutex);
list_for_each_entry(s, &tgt->sess_list, sess_list_entry) {
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
struct list_head *head = &s->sess_tgt_dev_list[i];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, head,
sess_tgt_dev_list_entry) {
if (mcmd->sess == tgt_dev->sess)
scst_call_dev_task_mgmt_fn_done(
mcmd, tgt_dev);
}
}
}
mutex_unlock(&scst_mutex);
break;
}
default:
PRINT_ERROR("Wrong task management function %d on "
"task_mgmt_fn_done() stage", mcmd->fn);
break;
}
tgt_done:
scst_call_task_mgmt_affected_cmds_done(mcmd);
res = scst_set_mcmd_next_state(mcmd);
@@ -5665,7 +5731,7 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
mcmd->state = SCST_MCMD_STATE_FINISHED;
if (scst_is_strict_mgmt_fn(mcmd->fn) && (mcmd->completed_cmd_count > 0))
mcmd->status = SCST_MGMT_STATUS_TASK_NOT_EXIST;
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_TASK_NOT_EXIST);
if (mcmd->fn < SCST_UNREG_SESS_TM)
TRACE(TRACE_MGMT, "TM fn %d (%p) finished, "

View File

@@ -537,7 +537,7 @@ static int do_on_free_cmd(struct vdisk_cmd *vcmd)
return res;
}
static int do_tm(struct vdisk_cmd *vcmd)
static int do_tm(struct vdisk_cmd *vcmd, int done)
{
struct scst_user_get_cmd *cmd = vcmd->cmd;
struct scst_user_reply_cmd *reply = vcmd->reply;
@@ -547,22 +547,26 @@ static int do_tm(struct vdisk_cmd *vcmd)
TRACE_ENTRY();
if (cmd->tm_cmd.fn <= SCST_TARGET_RESET)
TRACE(TRACE_MGMT, "TM fn %d (sess_h %"PRIx64", cmd_h_to_abort "
"%d)", cmd->tm_cmd.fn, cmd->tm_cmd.sess_h,
TRACE(TRACE_MGMT, "%s TM fn %d (sess_h %"PRIx64", "
"cmd_h_to_abort %d)", done ? "Done" : "Received",
cmd->tm_cmd.fn, cmd->tm_cmd.sess_h,
cmd->tm_cmd.cmd_h_to_abort);
else
TRACE_MGMT_DBG("TM fn %d (sess_h %"PRIx64", cmd_h_to_abort %d)",
TRACE_MGMT_DBG("%s TM fn %d (sess_h %"PRIx64", "
"cmd_h_to_abort %d)", done ? "Done" : "Received",
cmd->tm_cmd.fn, cmd->tm_cmd.sess_h,
cmd->tm_cmd.cmd_h_to_abort);
switch (cmd->tm_cmd.fn) {
case SCST_LUN_RESET:
case SCST_TARGET_RESET:
case SCST_PR_ABORT_ALL:
pthread_mutex_lock(&dev->dev_mutex);
dev->prevent_allow_medium_removal = 0;
pthread_mutex_unlock(&dev->dev_mutex);
break;
if (done) {
switch (cmd->tm_cmd.fn) {
case SCST_LUN_RESET:
case SCST_TARGET_RESET:
case SCST_PR_ABORT_ALL:
pthread_mutex_lock(&dev->dev_mutex);
dev->prevent_allow_medium_removal = 0;
pthread_mutex_unlock(&dev->dev_mutex);
break;
}
}
memset(reply, 0, sizeof(*reply));
@@ -791,8 +795,12 @@ again_poll:
res = do_on_free_cmd(&vcmd);
break;
case SCST_USER_TASK_MGMT:
res = do_tm(&vcmd);
case SCST_USER_TASK_MGMT_RECEIVED:
res = do_tm(&vcmd, 0);
break;
case SCST_USER_TASK_MGMT_DONE:
res = do_tm(&vcmd, 1);
#if DEBUG_TM_FN_IGNORE
if (dev->debug_tm_ignore) {
sleep(15);