- Adds generation of INQUERY DATA HAS CHANGED UA for changed devices during automati...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Mon, 10 Aug 2009 12:27:29 +0000 (12:27 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Mon, 10 Aug 2009 12:27:29 +0000 (12:27 +0000)
 - Requeue global UAs on delivery failure added
 - Minor fixes and cleanups

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@1031 d57e44dd-8a1f-0410-8b47-8ef2f437770f

scst/include/scst.h
scst/include/scst_const.h
scst/src/scst_lib.c
scst/src/scst_priv.h
scst/src/scst_targ.c

index 60cd142..b2c6f43 100644 (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
index bb7af8e..45c64bd 100644 (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
index cb139ca..d1d5c4d 100644 (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();
index 7ae0562..4c3ab86 100644 (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;
index 8039b51..69a37be 100644 (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: