mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-28 09:20:18 +00:00
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:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, "
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user