From 29ebc5ba12d2cfbda15fe3331e51d5f8e3a28598 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 8 Sep 2011 02:17:01 +0000 Subject: [PATCH] Web updates git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3850 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- www/aca.diff | 621 ++++++++++++++++++++++++++++++++++++++++++ www/comparison.html | 2 +- www/contributing.html | 9 + www/target_srp.html | 2 +- 4 files changed, 632 insertions(+), 2 deletions(-) create mode 100644 www/aca.diff diff --git a/www/aca.diff b/www/aca.diff new file mode 100644 index 000000000..bd1ef8e5f --- /dev/null +++ b/www/aca.diff @@ -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); diff --git a/www/comparison.html b/www/comparison.html index cd67cfff3..72fc41d0e 100644 --- a/www/comparison.html +++ b/www/comparison.html @@ -86,7 +86,7 @@ Performance 3 ***** 4 - *** **** **** + *** **** ****- Zero-copy passing data between target and diff --git a/www/contributing.html b/www/contributing.html index 83aad1f83..bddad8135 100644 --- a/www/contributing.html +++ b/www/contributing.html @@ -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.

+

Auto Contingent Allegiance (ACA)

+ +

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.

+ +

There is a patch aca.diff implementing ACA for SCST 1.0. Update of it for SCST 3.0 + is welcome!

+ diff --git a/www/target_srp.html b/www/target_srp.html index 5df1b7466..14f110eb4 100644 --- a/www/target_srp.html +++ b/www/target_srp.html @@ -62,7 +62,7 @@ It is maintained by Bart Van Assche.

This driver is mainline Linux kernel ready and going to be pushed to it together with other SCST patches.

-

The latest stable version is 2.0.0.

+

The latest stable version is 2.1.0.




Download