Files
scst/www/aca.diff
Vladislav Bolkhovitin 29ebc5ba12 Web updates
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3850 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2011-09-08 02:17:01 +00:00

622 lines
21 KiB
Diff

This patch is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, version 2
of the License.
--- scst/include/scst.h
+++ scst/include/scst.h
@@ -410,6 +410,12 @@ enum scst_exec_context {
/* Set if tgt_dev is RESERVED by another session */
#define SCST_TGT_DEV_RESERVED 1
+/* Set if the tgt_dev is in ACA state */
+#define SCST_TGT_DEV_ACA_ACTIVE 2
+
+/* Set if the tgt_dev is handling a task with an ACA attribute */
+#define SCST_TGT_DEV_ACA_CMD_ACTIVE 3
+
/* 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
@@ -1164,6 +1170,12 @@ struct scst_cmd {
/* Set if hq_cmd_count was incremented */
unsigned int hq_cmd_inced:1;
+ /* set if this command goes to the head of the queue (HQ or ACA) */
+ unsigned int hq_cmd:1;
+
+ /* set if this is a naca command */
+ unsigned int naca_cmd:1;
+
/*
* Set if scst_cmd_init_stage1_done() called and the target wants
* that the SN for the cmd won't be assigned until scst_restart_cmd()
@@ -1217,7 +1229,7 @@ struct scst_cmd {
#endif
/* List entry for tgt_dev's SN related lists */
- struct list_head sn_cmd_list_entry;
+ struct list_head deferred_cmd_list_entry;
/* Cmd's serial number, used to execute cmd's in order of arrival */
unsigned long sn;
@@ -2718,7 +2730,7 @@ int scst_check_local_events(struct scst_cmd *cmd);
* Returns the next state of the SCSI target state machine in case if command's
* completed abnormally.
*/
-int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd);
+int scst_get_cmd_abnormal_done_state(struct scst_cmd *cmd);
/*
* Sets state of the SCSI target state machine in case if command's completed
--- scst/src/scst_lib.c
+++ scst/src/scst_lib.c
@@ -683,7 +683,7 @@ out_free:
}
EXPORT_SYMBOL(scst_aen_done);
-int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
+int scst_get_cmd_abnormal_done_state(struct scst_cmd *cmd)
{
int res;
@@ -693,6 +693,14 @@ EXPORT_SYMBOL(scst_aen_done);
case SCST_CMD_STATE_INIT_WAIT:
case SCST_CMD_STATE_INIT:
case SCST_CMD_STATE_PRE_PARSE:
+ if (cmd->tgt_dev != NULL) {
+ int rc;
+ rc = scst_get_cdb_info(cmd);
+ if (rc == 0) {
+ int cbyte = cmd->cdb[cmd->cdb_len -1];
+ cmd->naca_cmd = (cbyte & CONTROL_BYTE_NACA_BIT) != 0;
+ }
+ }
case SCST_CMD_STATE_DEV_PARSE:
case SCST_CMD_STATE_DEV_DONE:
if (cmd->internal)
@@ -1221,6 +1229,8 @@ void scst_nexus_loss(struct scst_tgt_dev *tgt_dev,
/* With activity suspended the lock isn't needed, but let's be safe */
spin_lock_bh(&tgt_dev->tgt_dev_lock);
+ clear_bit(SCST_TGT_DEV_ACA_ACTIVE, &tgt_dev->tgt_dev_flags);
+ clear_bit(SCST_TGT_DEV_ACA_CMD_ACTIVE, &tgt_dev->tgt_dev_flags);
scst_free_all_UA(tgt_dev);
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
@@ -3367,6 +3377,8 @@ void scst_process_reset(struct scst_device *dev,
struct scst_session *sess = tgt_dev->sess;
spin_lock_bh(&tgt_dev->tgt_dev_lock);
+ clear_bit(SCST_TGT_DEV_ACA_ACTIVE, &tgt_dev->tgt_dev_flags);
+ clear_bit(SCST_TGT_DEV_ACA_CMD_ACTIVE, &tgt_dev->tgt_dev_flags);
scst_free_all_UA(tgt_dev);
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
@@ -3689,14 +3701,13 @@ struct scst_cmd *__scst_check_deferred_commands(st
restart:
list_for_each_entry_safe(cmd, t, &tgt_dev->deferred_cmd_list,
- sn_cmd_list_entry) {
- EXTRACHECKS_BUG_ON(cmd->queue_type ==
- SCST_CMD_QUEUE_HEAD_OF_QUEUE);
+ deferred_cmd_list_entry) {
+ EXTRACHECKS_BUG_ON(cmd->hq_cmd);
if (cmd->sn == expected_sn) {
TRACE_SN("Deferred command %p (sn %ld, set %d) found",
cmd, cmd->sn, cmd->sn_set);
tgt_dev->def_cmd_count--;
- list_del(&cmd->sn_cmd_list_entry);
+ list_del(&cmd->deferred_cmd_list_entry);
if (res == NULL)
res = cmd;
else {
@@ -3714,9 +3725,8 @@ restart:
goto out_unlock;
list_for_each_entry(cmd, &tgt_dev->skipped_sn_list,
- sn_cmd_list_entry) {
- EXTRACHECKS_BUG_ON(cmd->queue_type ==
- SCST_CMD_QUEUE_HEAD_OF_QUEUE);
+ deferred_cmd_list_entry) {
+ EXTRACHECKS_BUG_ON(cmd->hq_cmd);
if (cmd->sn == expected_sn) {
atomic_t *slot = cmd->sn_slot;
/*
@@ -3729,7 +3739,7 @@ restart:
(long long unsigned int)cmd->tag,
cmd->sn);
tgt_dev->def_cmd_count--;
- list_del(&cmd->sn_cmd_list_entry);
+ list_del(&cmd->deferred_cmd_list_entry);
spin_unlock_irq(&tgt_dev->sn_lock);
if (test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED,
&cmd->cmd_flags))
@@ -4019,7 +4029,7 @@ static void scst_unblock_cmds(struct scst_device *
list_del(&cmd->blocked_cmd_list_entry);
TRACE_MGMT_DBG("Adding blocked cmd %p to active cmd list", cmd);
spin_lock(&cmd->cmd_lists->cmd_list_lock);
- if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
+ if (unlikely(cmd->hq_cmd))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -4047,7 +4057,7 @@ static void __scst_unblock_deferred(struct scst_tg
out_of_sn_cmd->out_of_sn = 1;
spin_lock_irq(&tgt_dev->sn_lock);
tgt_dev->def_cmd_count++;
- list_add_tail(&out_of_sn_cmd->sn_cmd_list_entry,
+ list_add_tail(&out_of_sn_cmd->deferred_cmd_list_entry,
&tgt_dev->skipped_sn_list);
TRACE_SN("out_of_sn_cmd %p with sn %ld added to skipped_sn_list"
" (expected_sn %ld)", out_of_sn_cmd, out_of_sn_cmd->sn,
--- scst/src/scst_targ.c
+++ scst/src/scst_targ.c
@@ -40,6 +40,7 @@ static struct scst_cmd *__scst_find_cmd_by_tag(str
uint64_t tag);
static void scst_proccess_redirect_cmd(struct scst_cmd *cmd,
enum scst_exec_context context, int check_retries);
+static int scst_set_mcmd_next_state(struct scst_mgmt_cmd *mcmd);
static inline void scst_schedule_tasklet(struct scst_cmd *cmd)
{
@@ -280,7 +281,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
goto active;
}
- if (unlikely(cmd->queue_type >= SCST_CMD_QUEUE_ACA)) {
+ if (unlikely(cmd->queue_type > SCST_CMD_QUEUE_ACA)) {
PRINT_ERROR("Unsupported queue type %d", cmd->queue_type);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_message));
@@ -300,6 +301,10 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION)) {
if (rc == 0) {
/* Target driver preliminary completed cmd */
+ if (cmd->tgt_dev != NULL) {
+ atomic_inc(&cmd->tgt_dev->tgt_dev_cmd_count);
+ atomic_inc(&cmd->dev->dev_cmd_count);
+ }
scst_set_cmd_abnormal_done_state(cmd);
}
}
@@ -328,7 +333,7 @@ active:
case SCST_CONTEXT_THREAD:
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
TRACE_DBG("Adding cmd %p to active cmd list", cmd);
- if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
+ if (unlikely(cmd->hq_cmd))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -434,13 +439,8 @@ static int scst_pre_parse(struct scst_cmd *cmd)
}
}
- if (unlikely(cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT)) {
- PRINT_ERROR("NACA bit in control byte CDB is not supported "
- "(opcode 0x%02x)", cmd->cdb[0]);
- scst_set_cmd_error(cmd,
- SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
- goto out_xmit;
- }
+ cmd->naca_cmd = (cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT) !=0;
+ TRACE(TRACE_SCSI,"cmd %p NACA bit %d", cmd, cmd->naca_cmd);
if (unlikely(cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_LINK_BIT)) {
PRINT_ERROR("Linked commands are not supported "
@@ -537,6 +537,9 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
} else
state = SCST_CMD_STATE_PREPARE_SPACE;
+ if (cmd->naca_cmd)
+ cmd->inc_expected_sn_on_done = 1;
+
if (cmd->data_len == -1)
cmd->data_len = cmd->bufflen;
@@ -1069,7 +1072,7 @@ static void scst_proccess_redirect_cmd(struct scst
scst_check_retries(cmd->tgt);
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
TRACE_DBG("Adding cmd %p to active cmd list", cmd);
- if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
+ if (unlikely(cmd->hq_cmd))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -2252,11 +2255,36 @@ static int scst_send_for_exec(struct scst_cmd **ac
if (unlikely(cmd->internal))
goto exec;
- if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
+ /* this will cause HQ & ACA commands to goto exec */
+ if (unlikely(cmd->hq_cmd))
goto exec;
sBUG_ON(!cmd->sn_set);
+ /* Handla ACA */
+ if (unlikely(test_bit(SCST_TGT_DEV_ACA_ACTIVE, &tgt_dev->tgt_dev_flags))) {
+ spin_lock_irq(&tgt_dev->sn_lock);
+ TRACE_DBG("ACA_ACTIVE: handling exec cmd %p queue type %d", cmd, cmd->queue_type);
+ if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
+ TRACE_MGMT_DBG("Aborting out of sn cmd %p "
+ "(tag %llu, sn %lu)", cmd,
+ (long long unsigned)cmd->tag, cmd->sn);
+ spin_unlock_irq(&tgt_dev->sn_lock);
+ scst_set_cmd_abnormal_done_state(cmd);
+ res = SCST_CMD_STATE_RES_CONT_SAME;
+ goto out;
+ }
+
+ /* defer the command */
+ TRACE(TRACE_SCSI, "ACA active for tgt_dev %p: deferring cmd %p",
+ tgt_dev, cmd);
+ list_add_tail(&cmd->deferred_cmd_list_entry,
+ &tgt_dev->deferred_cmd_list);
+ spin_unlock_irq(&tgt_dev->sn_lock);
+ res = SCST_CMD_STATE_RES_CONT_NEXT;
+ goto out;
+ }
+
expected_sn = tgt_dev->expected_sn;
/* Optimized for lockless fast path */
if ((cmd->sn != expected_sn) || (tgt_dev->hq_cmd_count > 0)) {
@@ -2291,7 +2319,7 @@ static int scst_send_for_exec(struct scst_cmd **ac
TRACE_SN("Deferring cmd %p (sn=%ld, set %d, "
"expected_sn=%ld)", cmd, cmd->sn,
cmd->sn_set, expected_sn);
- list_add_tail(&cmd->sn_cmd_list_entry,
+ list_add_tail(&cmd->deferred_cmd_list_entry,
&tgt_dev->deferred_cmd_list);
res = SCST_CMD_STATE_RES_CONT_NEXT;
}
@@ -2435,6 +2463,72 @@ static int scst_check_auto_sense(struct scst_cmd *
return res;
}
+/* called under no locks*/
+static int scst_clear_aca(struct scst_mgmt_cmd* mcmd, struct scst_tgt_dev *tgt_dev)
+{
+ unsigned long flags;
+ struct scst_cmd *cmd, *tcmd;
+ struct scst_session *sess;
+ int res = 0;
+
+ TRACE_ENTRY();
+
+ TRACE_MGMT_DBG("Clearing ACA for tgt_dev %p (lun %lld)",
+ tgt_dev, tgt_dev->lun);
+ if (!test_bit(SCST_TGT_DEV_ACA_ACTIVE, &tgt_dev->tgt_dev_flags)) {
+ /* reject CLEAR_ACA when not in ACA state */
+ TRACE_MGMT_DBG("Rejecting CLEAR_ACA for tgt_dev %p (lun %lld)",
+ tgt_dev, tgt_dev->lun);
+ res = 1;
+ goto out;
+ }
+
+ clear_bit(SCST_TGT_DEV_ACA_ACTIVE, &tgt_dev->tgt_dev_flags);
+ if (test_bit(SCST_TGT_DEV_ACA_CMD_ACTIVE, &tgt_dev->tgt_dev_flags) && (mcmd)) {
+ sess = tgt_dev->sess;
+ spin_lock_irqsave(&sess->sess_list_lock, flags);
+ TRACE_DBG("Searching in search cmd list (sess=%p) "
+ "for an ACA command", sess);
+ list_for_each_entry(cmd, &sess->search_cmd_list,
+ search_cmd_list_entry) {
+ if ((cmd->tgt_dev == tgt_dev) &&
+ (cmd->queue_type == SCST_CMD_QUEUE_ACA)) {
+ /* Found the ACA command - abort it */
+ scst_abort_cmd(cmd, mcmd, 0, 0);
+ res = -1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&sess->sess_list_lock, flags);
+ }
+
+ spin_lock_irq(&tgt_dev->sn_lock);
+ list_for_each_entry_safe(cmd, tcmd,
+ &tgt_dev->deferred_cmd_list,
+ deferred_cmd_list_entry) {
+
+ TRACE_MGMT_DBG("Move cmd %p (sn %lu) "
+ "from deferred list to active_list",
+ cmd, cmd->sn);
+
+ list_del(&cmd->deferred_cmd_list_entry);
+ 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);
+ tgt_dev->def_cmd_count--;
+ }
+ spin_unlock_irq(&tgt_dev->sn_lock);
+
+ if (mcmd != NULL)
+ res = scst_set_mcmd_next_state(mcmd);
+
+out:
+ TRACE_EXIT_RES(res);
+ return res;
+}
+
static int scst_pre_dev_done(struct scst_cmd *cmd)
{
int res = SCST_CMD_STATE_RES_CONT_SAME, rc;
@@ -2506,14 +2600,14 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
if (buflen > SCST_INQ_BYTE3) {
#ifdef CONFIG_SCST_EXTRACHECKS
if (buffer[SCST_INQ_BYTE3] & SCST_INQ_NORMACA_BIT) {
- PRINT_INFO("NormACA set for device: "
- "lun=%lld, type 0x%02x. Clear it, "
- "since it's unsupported.",
+ TRACE_DBG("NormACA set for device: "
+ "lun=%lld, type 0x%02x "
+ "NACA is only supported for "
+ "TST=1 & QErr=0.",
(long long unsigned int)cmd->lun,
buffer[0]);
}
#endif
- buffer[SCST_INQ_BYTE3] &= ~SCST_INQ_NORMACA_BIT;
} else if (buflen != 0) {
PRINT_ERROR("%s", "Unable to get INQUIRY "
"buffer");
@@ -2761,9 +2855,6 @@ static int scst_dev_done(struct scst_cmd *cmd)
if (likely(cmd->dec_on_dev_needed))
scst_dec_on_dev_cmd(cmd);
- if (cmd->inc_expected_sn_on_done && cmd->sent_for_exec)
- scst_inc_check_expected_sn(cmd);
-
if (unlikely(cmd->internal))
cmd->state = SCST_CMD_STATE_FINISHED_INTERNAL;
@@ -2794,15 +2885,48 @@ static int scst_pre_xmit_response(struct scst_cmd
schedule_timeout_uninterruptible(HZ);
}
#endif
+ if (cmd->queue_type == SCST_CMD_QUEUE_ACA)
+ TRACE_DBG("ACA command %p, tgt_dev %p, status %d, naca %d",cmd, cmd->tgt_dev, cmd->status, cmd->naca_cmd);
if (likely(cmd->tgt_dev != NULL)) {
+ if (cmd->inc_expected_sn_on_done && cmd->sent_for_exec)
+ scst_inc_check_expected_sn(cmd);
+
+ /* Enter\Exit ACA state */
+ if (cmd->status == SAM_STAT_CHECK_CONDITION) {
+ /* If the command attribute is ACA, exit from ACA state */
+ if ((cmd->queue_type == SCST_CMD_QUEUE_ACA) &&
+ (test_bit(SCST_TGT_DEV_ACA_ACTIVE, &cmd->tgt_dev->tgt_dev_flags))) {
+ TRACE(TRACE_SCSI, "ACA: tgt_dev %p exits from ACA state "
+ "because of cmd %p", cmd->tgt_dev, cmd);
+ scst_clear_aca(NULL, cmd->tgt_dev);
+ }
+
+ /* If this is a NACA command enter ACA state */
+ if (cmd->naca_cmd) {
+ int cmd_count = atomic_read(&cmd->tgt_dev->tgt_dev_cmd_count);
+ set_bit(SCST_TGT_DEV_ACA_ACTIVE, &cmd->tgt_dev->tgt_dev_flags);
+ TRACE(TRACE_SCSI, "ACA: tgt_dev %p enters ACA state because "
+ "of cmd %p (tgt_dev_cmd_count = %d)",
+ cmd->tgt_dev,
+ cmd,
+ cmd_count);
+
+ PRINT_BUFF_FLAG(TRACE_SCSI, "cdb that caused the ACA state",
+ cmd->cdb, cmd->cdb_len);
+ }
+ }
+
+ if (unlikely(test_bit(SCST_TGT_DEV_ACA_ACTIVE, &cmd->tgt_dev->tgt_dev_flags)))
+ clear_bit(SCST_TGT_DEV_ACA_CMD_ACTIVE, &cmd->tgt_dev->tgt_dev_flags);
+
atomic_dec(&cmd->tgt_dev->tgt_dev_cmd_count);
atomic_dec(&cmd->dev->dev_cmd_count);
/* If expected values not set, expected direction is UNKNOWN */
if (cmd->expected_data_direction == SCST_DATA_WRITE)
atomic_dec(&cmd->dev->write_cmd_count);
- if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
+ if (unlikely(cmd->hq_cmd))
scst_on_hq_cmd_response(cmd);
if (unlikely(!cmd->sent_for_exec)) {
@@ -3128,11 +3252,13 @@ ordered:
break;
case SCST_CMD_QUEUE_HEAD_OF_QUEUE:
- TRACE_SN("HQ cmd %p (op %x)", cmd, cmd->cdb[0]);
+ case SCST_CMD_QUEUE_ACA:
+ TRACE_SN("HQ or ACA (%d) cmd %p (op %x)", cmd->queue_type, cmd, cmd->cdb[0]);
spin_lock_irqsave(&tgt_dev->sn_lock, flags);
tgt_dev->hq_cmd_count++;
spin_unlock_irqrestore(&tgt_dev->sn_lock, flags);
cmd->hq_cmd_inced = 1;
+ cmd->hq_cmd = 1;
goto out;
default:
@@ -3223,7 +3349,9 @@ static int scst_translate_lun(struct scst_cmd *cmd
*/
static int __scst_init_cmd(struct scst_cmd *cmd)
{
+ struct scst_tgt_dev *tgt_dev;
int res = 0;
+ bool done = false;
TRACE_ENTRY();
@@ -3234,28 +3362,74 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
cmd->state = SCST_CMD_STATE_PRE_PARSE;
- cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count);
- if (unlikely(cnt > SCST_MAX_TGT_DEV_COMMANDS)) {
- TRACE(TRACE_MGMT_MINOR,
- "Too many pending commands (%d) in "
- "session, returning BUSY to initiator \"%s\"",
- cnt, (cmd->sess->initiator_name[0] == '\0') ?
- "Anonymous" : cmd->sess->initiator_name);
- failure = true;
- }
+ /* Handle ACA for TST=1 QErr=0*/
+ tgt_dev = cmd->tgt_dev;
+ if (unlikely(test_bit(SCST_TGT_DEV_ACA_ACTIVE,
+ &tgt_dev->tgt_dev_flags))) {
+ /* Terminate commands without ACA attribute,
+ * Only one ACA command should be handled at a time */
+ if ((cmd->queue_type != SCST_CMD_QUEUE_ACA) ||
+ test_bit(SCST_TGT_DEV_ACA_CMD_ACTIVE,
+ &tgt_dev->tgt_dev_flags)) {
+ TRACE(TRACE_SCSI|TRACE_DEBUG,
+ "cmd %p terminated with ACA_ACTIVE "
+ "(queue_type=%d, tgt_dev %p)",
+ cmd, cmd->queue_type,tgt_dev);
+ atomic_inc(&cmd->tgt_dev->tgt_dev_cmd_count);
+ atomic_inc(&cmd->dev->dev_cmd_count);
+ scst_set_cmd_error_status(cmd,
+ SAM_STAT_ACA_ACTIVE);
+ scst_set_cmd_abnormal_done_state(cmd);
+ failure = true;
+ done = true;
+ res = -1;
+ } else {
+ TRACE(TRACE_SCSI|TRACE_DEBUG,
+ "tgt_dev %p received ACA CMD %p ",
+ tgt_dev, cmd);
+ set_bit(SCST_TGT_DEV_ACA_CMD_ACTIVE, &tgt_dev->tgt_dev_flags);
+ atomic_inc(&cmd->tgt_dev->tgt_dev_cmd_count);
+ atomic_inc(&cmd->dev->dev_cmd_count);
+ }
+ } else {
+ /* Terminate commands with ACA attribute when not
+ * in ACA state*/
+ if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_ACA)) {
+ TRACE(TRACE_SCSI|TRACE_DEBUG,
+ "ACA cmd %p terminated because ITL "
+ "nexus is not in ACA state "
+ "(tgt dev %p)", cmd, tgt_dev);
+ scst_set_cmd_error(cmd,
+ SCST_LOAD_SENSE(scst_sense_invalid_message));
+ scst_set_cmd_abnormal_done_state(cmd);
+ failure = true;
+ done = true;
+ res = -1;
+ }
- cnt = atomic_inc_return(&cmd->dev->dev_cmd_count);
- if (unlikely(cnt > SCST_MAX_DEV_COMMANDS)) {
- if (!failure) {
+ cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count);
+ if (unlikely(cnt > SCST_MAX_TGT_DEV_COMMANDS)) {
TRACE(TRACE_MGMT_MINOR,
- "Too many pending device "
- "commands (%d), returning BUSY to "
- "initiator \"%s\"", cnt,
- (cmd->sess->initiator_name[0] == '\0') ?
- "Anonymous" :
- cmd->sess->initiator_name);
+ "Too many pending commands (%d) in "
+ "session, returning BUSY to initiator \"%s\"",
+ cnt, (cmd->sess->initiator_name[0] == '\0') ?
+ "Anonymous" : cmd->sess->initiator_name);
failure = true;
}
+
+ cnt = atomic_inc_return(&cmd->dev->dev_cmd_count);
+ if (unlikely(cnt > SCST_MAX_DEV_COMMANDS)) {
+ if (!failure) {
+ TRACE(TRACE_MGMT_MINOR,
+ "Too many pending device "
+ "commands (%d), returning BUSY to "
+ "initiator \"%s\"", cnt,
+ (cmd->sess->initiator_name[0] == '\0') ?
+ "Anonymous" :
+ cmd->sess->initiator_name);
+ failure = true;
+ }
+ }
}
/* If expected values not set, expected direction is UNKNOWN */
@@ -3263,7 +3437,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
atomic_inc(&cmd->dev->write_cmd_count);
if (unlikely(failure))
- goto out_busy;
+ goto out_failure;
if (!cmd->set_sn_on_restart_cmd)
scst_cmd_set_sn(cmd);
@@ -3279,9 +3453,11 @@ out:
TRACE_EXIT_RES(res);
return res;
-out_busy:
- scst_set_busy(cmd);
- scst_set_cmd_abnormal_done_state(cmd);
+out_failure:
+ if (!done) {
+ scst_set_busy(cmd);
+ scst_set_cmd_abnormal_done_state(cmd);
+ }
goto out;
}
@@ -3343,7 +3519,7 @@ restart:
spin_lock(&cmd->cmd_lists->cmd_list_lock);
TRACE_MGMT_DBG("Adding cmd %p to active cmd list", cmd);
- if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
+ if (unlikely(cmd->hq_cmd))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -4138,9 +4314,9 @@ static void scst_unblock_aborted_cmds(int scst_mut
spin_lock(&tgt_dev->sn_lock);
list_for_each_entry_safe(cmd, tcmd,
&tgt_dev->deferred_cmd_list,
- sn_cmd_list_entry) {
+ deferred_cmd_list_entry) {
if (__scst_check_unblock_aborted_cmd(cmd,
- &cmd->sn_cmd_list_entry)) {
+ &cmd->deferred_cmd_list_entry)) {
TRACE_MGMT_DBG("Unblocked aborted SN "
"cmd %p (sn %lu)",
cmd, cmd->sn);
@@ -4773,12 +4949,13 @@ static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd
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) */
+ res = scst_clear_aca(mcmd, mcmd->mcmd_tgt_dev);
+ if (res > 0) {
+ res = 0;
+ mcmd->status = SCST_MGMT_STATUS_REJECTED;
+ goto out_done;
}
- goto out_done;
+ break;
default:
PRINT_ERROR("Unknown task management function %d", mcmd->fn);
--- scst/src/dev_handlers/scst_user.c
+++ scst/src/dev_handlers/scst_user.c
@@ -1061,8 +1061,9 @@ static void dev_user_add_to_ready(struct scst_user
do_wake = 1;
} else {
if ((ucmd->cmd != NULL) &&
- unlikely((ucmd->cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))) {
- TRACE_DBG("Adding HQ ucmd %p to head of ready cmd list",
+ unlikely((ucmd->cmd->hq_cmd))) {
+ TRACE_DBG("Adding HQ or ACA (%d) ucmd %p to head of ready cmd list",
+ ucmd->cmd->queue_type,
ucmd);
list_add(&ucmd->ready_cmd_list_entry,
&dev->ready_cmd_list);