Web updates

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3850 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2011-09-08 02:17:01 +00:00
parent 5a4ee2342b
commit 29ebc5ba12
4 changed files with 632 additions and 2 deletions

621
www/aca.diff Normal file
View File

@@ -0,0 +1,621 @@
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);

View File

@@ -86,7 +86,7 @@
<tr>
<td align="left"><b>Performance <sup><A HREF="#3">3</A></sup></b></td> <td> ***** <sup>
<A HREF="#4">4</A>
</sup></td> <td> ***</td> <td> **** </td> <td> **** </td>
</sup></td> <td> ***</td> <td> **** </td> <td> ****- </td>
</tr>
<tr>
<th align="left"> Zero-copy passing data between target and

View File

@@ -277,6 +277,15 @@
and only for cases where it's really needed, like device unregistration. This is a very tricky task, because
all the internal SCST locking should be reimplemented.</p>
<A NAME="ACA"></A><h3>Auto Contingent Allegiance (ACA)</h3>
<p>Auto Contingent Allegiance (ACA) - is a powerful SCSI state, where in case of some special conditions,
like a command finished with an error, all subsequent SCSI commands are delayed or aborted by SCSI device.
It is necessary to protect order of queued commands after errors. See SAM for more details.</p>
<p>There is a patch <a href="aca.diff">aca.diff</a> implementing ACA for SCST 1.0. Update of it for SCST 3.0
is welcome!</p>
</div>
</div>
</div>

View File

@@ -62,7 +62,7 @@
It is maintained by Bart Van Assche.</p>
<p>This driver is mainline Linux kernel ready and going to be pushed to it
together with other SCST patches.</p>
<p>The latest stable version is 2.0.0.</p>
<p>The latest stable version is 2.1.0.</p>
</p><br><br><br>
<p class="post-footer align-right">
<a href="downloads.html" class="readmore">Download</a>