- 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
This commit is contained in:
Vladislav Bolkhovitin
2009-08-10 12:27:29 +00:00
parent 3d227b8f73
commit a6189e9096
5 changed files with 122 additions and 31 deletions
+11 -2
View File
@@ -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
+1 -5
View File
@@ -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
+85 -4
View File
@@ -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();
+3
View File
@@ -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;
+22 -20
View File
@@ -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: