From a6189e9096745887bc620baf51a677ed9585c45c Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Mon, 10 Aug 2009 12:27:29 +0000 Subject: [PATCH] - Adds generation of INQUERY DATA HAS CHANGED UA for changed devices during automatic sessions reassignment - Requeue global UAs on delivery failure added - Minor fixes and cleanups git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1031 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scst.h | 13 +++++- scst/include/scst_const.h | 6 +-- scst/src/scst_lib.c | 89 +++++++++++++++++++++++++++++++++++++-- scst/src/scst_priv.h | 3 ++ scst/src/scst_targ.c | 42 +++++++++--------- 5 files changed, 122 insertions(+), 31 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 60cd14262..b2c6f43de 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1677,12 +1677,15 @@ struct scst_tgt_dev { struct scst_session *sess; /* corresponding session */ struct scst_acg_dev *acg_dev; /* corresponding acg_dev */ - /* list entry in dev->dev_tgt_dev_list */ + /* List entry in dev->dev_tgt_dev_list */ struct list_head dev_tgt_dev_list_entry; - /* internal tmp list entry */ + /* Internal tmp list entry */ struct list_head extra_tgt_dev_list_entry; + /* Set if INQUIRY DATA HAS CHANGED UA is needed */ + unsigned int inq_changed_ua_needed:1; + /* * Stored Unit Attention sense and its length for possible * subsequent REQUEST SENSE. Both protected by tgt_dev_lock. @@ -3009,6 +3012,12 @@ int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic, void scst_set_sense(uint8_t *buffer, int len, bool d_sense, int key, int asc, int ascq); +/* + * Returns true if the sense is valid and carrying a Unit Attention or + * false otherwise. + */ +bool scst_is_ua_sense(const uint8_t *sense, int len); + /* * Returnes true if sense matches to (key, asc, ascq) and false otherwise. * Valid_mask is one or several SCST_SENSE_*_VALID constants setting valid diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index bb7af8eea..45c64bd1d 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -139,11 +139,6 @@ enum scst_cmd_queue_type { #define SCST_NO_SENSE(sense) ((sense != NULL) && \ (((const uint8_t *)(sense))[2] == 0)) -static inline int scst_is_ua_sense(const uint8_t *sense) -{ - return SCST_SENSE_VALID(sense) && (sense[2] == UNIT_ATTENTION); -} - /************************************************************* ** Sense data for the appropriate errors. Can be used with ** scst_set_cmd_error() @@ -170,6 +165,7 @@ static inline int scst_is_ua_sense(const uint8_t *sense) #define scst_sense_cleared_by_another_ini_UA UNIT_ATTENTION, 0x2F, 0 #define scst_sense_capacity_data_changed UNIT_ATTENTION, 0x2A, 0x9 #define scst_sense_reported_luns_data_changed UNIT_ATTENTION, 0x3F, 0xE +#define scst_sense_inquery_data_changed UNIT_ATTENTION, 0x3F, 0x3 /************************************************************* * SCSI opcodes not listed anywhere else diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index cb139cadc..d1d5c4d44 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -259,6 +259,31 @@ out: } EXPORT_SYMBOL(scst_analyze_sense); +bool scst_is_ua_sense(const uint8_t *sense, int len) +{ + if (SCST_SENSE_VALID(sense)) + return scst_analyze_sense(sense, len, + SCST_SENSE_KEY_VALID, UNIT_ATTENTION, 0, 0); + else + return false; +} +EXPORT_SYMBOL(scst_is_ua_sense); + +bool scst_is_ua_global(const uint8_t *sense, int len) +{ + bool res; + + /* Changing it don't forget to change scst_requeue_ua() as well!! */ + + if (scst_analyze_sense(sense, len, SCST_SENSE_ALL_VALID, + SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed))) + res = true; + else + res = false; + + return res; +} + void scst_check_convert_sense(struct scst_cmd *cmd) { bool d_sense; @@ -702,6 +727,29 @@ out_free: } EXPORT_SYMBOL(scst_aen_done); +void scst_requeue_ua(struct scst_cmd *cmd) +{ + TRACE_ENTRY(); + + if (scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + SCST_SENSE_ALL_VALID, + SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed))) { + TRACE_MGMT_DBG("Requeuing REPORTED LUNS DATA CHANGED UA " + "for delivery failed cmd %p", cmd); + mutex_lock(&scst_mutex); + scst_queue_report_luns_changed_UA(cmd->sess, + SCST_SET_UA_FLAG_AT_HEAD); + mutex_unlock(&scst_mutex); + } else { + TRACE_MGMT_DBG("Requeuing UA for delivery failed cmd %p", cmd); + scst_check_set_UA(cmd->tgt_dev, cmd->sense, + cmd->sense_bufflen, SCST_SET_UA_FLAG_AT_HEAD); + } + + TRACE_EXIT(); + return; +} + /* The activity supposed to be suspended and scst_mutex held */ static void scst_check_reassign_sess(struct scst_session *sess) { @@ -711,7 +759,7 @@ static void scst_check_reassign_sess(struct scst_session *sess) struct list_head *shead; struct scst_tgt_dev *tgt_dev; bool luns_changed = false; - bool add_failed, something_freed; + bool add_failed, something_freed, not_needed_freed = false; TRACE_ENTRY(); @@ -733,6 +781,8 @@ static void scst_check_reassign_sess(struct scst_session *sess) retry_add: add_failed = false; list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) { + unsigned int inq_changed_ua_needed = 0; + for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { shead = &sess->sess_tgt_dev_list_hash[i]; @@ -747,7 +797,8 @@ retry_add: (unsigned long long)tgt_dev->lun); tgt_dev->acg_dev = acg_dev; goto next; - } + } else if (tgt_dev->lun == acg_dev->lun) + inq_changed_ua_needed = 1; } } @@ -761,11 +812,15 @@ retry_add: add_failed = true; break; } + + tgt_dev->inq_changed_ua_needed = inq_changed_ua_needed || + not_needed_freed; next: continue; } something_freed = false; + not_needed_freed = true; for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { struct scst_tgt_dev *t; shead = &sess->sess_tgt_dev_list_hash[i]; @@ -795,9 +850,35 @@ next: old_acg->acg_name, acg->acg_name); list_move_tail(&sess->acg_sess_list_entry, &acg->acg_sess_list); - if (luns_changed) + if (luns_changed) { + uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; + scst_report_luns_changed_sess(sess); + for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { + shead = &sess->sess_tgt_dev_list_hash[i]; + + list_for_each_entry(tgt_dev, shead, + sess_tgt_dev_list_entry) { + if (tgt_dev->inq_changed_ua_needed) { + TRACE_MGMT_DBG("sess %p: Setting " + "INQUIRY DATA HAS CHANGED UA " + "(tgt_dev %p)", sess, tgt_dev); + + tgt_dev->inq_changed_ua_needed = 0; + + scst_set_sense(sense_buffer, + sizeof(sense_buffer), + tgt_dev->dev->d_sense, + SCST_LOAD_SENSE(scst_sense_inquery_data_changed)); + + scst_check_set_UA(tgt_dev, sense_buffer, + sizeof(sense_buffer), 0); + } + } + } + } + out: TRACE_EXIT(); return; @@ -4164,7 +4245,7 @@ static void scst_check_internal_sense(struct scst_device *dev, int result, SCST_LOAD_SENSE(scst_sense_reset_UA)); scst_dev_check_set_UA(dev, NULL, sense, sense_len); } else if ((status_byte(result) == CHECK_CONDITION) && - SCST_SENSE_VALID(sense) && scst_is_ua_sense(sense)) + scst_is_ua_sense(sense, sense_len)) scst_dev_check_set_UA(dev, NULL, sense, sense_len); TRACE_EXIT(); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 7ae0562aa..4c3ab8613 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -434,6 +434,9 @@ void scst_process_reset(struct scst_device *dev, struct scst_session *originator, struct scst_cmd *exclude_cmd, struct scst_mgmt_cmd *mcmd, bool setUA); +bool scst_is_ua_global(const uint8_t *sense, int len); +void scst_requeue_ua(struct scst_cmd *cmd); + static inline bool scst_is_ua_command(struct scst_cmd *cmd) { return (cmd->op_flags & SCST_SKIP_UA) == 0; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 8039b510e..69a37be18 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -2425,7 +2425,7 @@ static int scst_check_sense(struct scst_cmd *cmd) cmd->sense_bufflen); /* Check Unit Attention Sense Key */ - if (scst_is_ua_sense(cmd->sense)) { + if (scst_is_ua_sense(cmd->sense, cmd->sense_bufflen)) { if (scst_analyze_sense(cmd->sense, cmd->sense_bufflen, SCST_SENSE_ASC_VALID, 0, SCST_SENSE_ASC_UA_RESET, 0)) { @@ -2653,8 +2653,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd) /* Check for MODE PARAMETERS CHANGED UA */ if ((cmd->dev->scsi_dev != NULL) && (cmd->status == SAM_STAT_CHECK_CONDITION) && - SCST_SENSE_VALID(cmd->sense) && - scst_is_ua_sense(cmd->sense) && + scst_is_ua_sense(cmd->sense, cmd->sense_bufflen) && scst_analyze_sense(cmd->sense, cmd->sense_bufflen, SCST_SENSE_ASCx_VALID, 0, 0x2a, 0x01)) { @@ -2717,8 +2716,7 @@ static int scst_mode_select_checks(struct scst_cmd *cmd) scst_obtain_device_parameters(dev); } } else if ((cmd->status == SAM_STAT_CHECK_CONDITION) && - SCST_SENSE_VALID(cmd->sense) && - scst_is_ua_sense(cmd->sense) && + scst_is_ua_sense(cmd->sense, cmd->sense_bufflen) && /* mode parameters changed */ (scst_analyze_sense(cmd->sense, cmd->sense_bufflen, SCST_SENSE_ASCx_VALID, @@ -3112,6 +3110,21 @@ static int scst_finish_cmd(struct scst_cmd *cmd) TRACE_ENTRY(); + if (unlikely(cmd->delivery_status != SCST_CMD_DELIVERY_SUCCESS)) { + if ((cmd->tgt_dev != NULL) && + scst_is_ua_sense(cmd->sense, cmd->sense_bufflen)) { + /* This UA delivery failed, so we need to requeue it */ + if (scst_cmd_atomic(cmd) && + scst_is_ua_global(cmd->sense, cmd->sense_bufflen)) { + TRACE_MGMT_DBG("Requeuing of global UA for " + "failed cmd %p needs a thread", cmd); + res = SCST_CMD_STATE_RES_NEED_THREAD; + goto out; + } + scst_requeue_ua(cmd); + } + } + atomic_dec(&sess->sess_cmd_count); spin_lock_irq(&sess->sess_list_lock); @@ -3129,21 +3142,13 @@ static int scst_finish_cmd(struct scst_cmd *cmd) scst_finish_cmd_mgmt(cmd); } - if (unlikely(cmd->delivery_status != SCST_CMD_DELIVERY_SUCCESS)) { - if ((cmd->tgt_dev != NULL) && - scst_is_ua_sense(cmd->sense)) { - /* This UA delivery failed, so requeue it */ - TRACE_MGMT_DBG("Requeuing UA for delivery failed cmd " - "%p", cmd); - scst_check_set_UA(cmd->tgt_dev, cmd->sense, - cmd->sense_bufflen, SCST_SET_UA_FLAG_AT_HEAD); - } - } + __scst_cmd_put(cmd); res = SCST_CMD_STATE_RES_CONT_NEXT; +out: TRACE_EXIT_HRES(res); return res; } @@ -3170,10 +3175,9 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd) scst_check_debug_sn(cmd); - if (cmd->dev->queue_alg == - SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) { + if (cmd->dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) { /* - * Not the best way, but well enough until there will be a + * Not the best way, but good enough until there is a * possibility to specify queue type during pass-through * commands submission. */ @@ -3633,8 +3637,6 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) case SCST_CMD_STATE_FINISHED: res = scst_finish_cmd(cmd); - EXTRACHECKS_BUG_ON(res == - SCST_CMD_STATE_RES_NEED_THREAD); break; case SCST_CMD_STATE_FINISHED_INTERNAL: