A bunch of minor fixes and important cleanups. Particularly:
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 9 Apr 2009 10:07:31 +0000 (10:07 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 9 Apr 2009 10:07:31 +0000 (10:07 +0000)
 - More fixes on circular dependency between target_mutex and scst_mutex
 - Docs updated
 - Sense handling cleanups

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

12 files changed:
iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/nthread.c
iscsi-scst/kernel/session.c
scst/README
scst/README_in-tree
scst/include/scst.h
scst/src/dev_handlers/scst_user.c
scst/src/scst_debug.c
scst/src/scst_lib.c
scst/src/scst_priv.h
scst/src/scst_targ.c

index 697e212..2e09be1 100644 (file)
@@ -2706,6 +2706,12 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
        if (unlikely(old_state != ISCSI_CMD_STATE_RESTARTED)) {
                TRACE_DBG("req %p on %d state", req, old_state);
 
+               /*
+                * We could preliminary have finished req before we knew its
+                * device, so check if we return correct sense format.
+                */
+               scst_check_convert_sense(scst_cmd);
+
                create_status_rsp(req, status, sense, sense_len);
 
                switch (old_state) {
index 680efa6..5ec817c 100644 (file)
@@ -123,7 +123,6 @@ struct iscsi_session {
        struct iscsi_session *sess_reinst_successor;
        unsigned int sess_reinstating:1;
        unsigned int sess_shutting_down:1;
-       unsigned int deleted_from_session_list:1;
 
        /* All don't need any protection */
        char *initiator_name;
@@ -458,7 +457,7 @@ extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
 extern void sess_enable_reinstated_sess(struct iscsi_session *);
 extern int session_add(struct iscsi_target *, struct iscsi_kern_session_info *);
 extern int session_del(struct iscsi_target *, u64);
-extern int session_free(struct iscsi_session *session);
+extern int session_free(struct iscsi_session *session, bool del);
 
 /* params.c */
 extern int iscsi_param_set(struct iscsi_target *,
index 5cb1c67..acc05d1 100644 (file)
@@ -552,18 +552,7 @@ static void close_conn(struct iscsi_conn *conn)
 
        if (list_empty(&session->conn_list)) {
                sBUG_ON(session->sess_reinst_successor != NULL);
-
-               list_del(&session->session_list_entry);
-               session->deleted_from_session_list = 1;
-
-               mutex_unlock(&target->target_mutex);
-               if (session->scst_sess != NULL) {
-                       scst_unregister_session(session->scst_sess, 1, NULL);
-                       session->scst_sess = NULL;
-               }
-               mutex_lock(&target->target_mutex);
-
-               session_free(session);
+               session_free(session, true);
        }
 
        mutex_unlock(&target->target_mutex);
index 2014975..8edac12 100644 (file)
@@ -196,7 +196,7 @@ int session_add(struct iscsi_target *target,
                 * Mutex target_mgmt_mutex won't allow to add connections to
                 * the new session after target_mutex was dropped, so it's safe
                 * to replace the initial UA without it. We can't do it under
-                * target_mutex, because otherwise we will establish a
+                * target_mutex, because otherwise we can establish a
                 * circular locking dependency between target_mutex and
                 * scst_mutex in SCST core (iscsi_report_aen() called by
                 * SCST core under scst_mutex).
@@ -213,13 +213,15 @@ out_err_unlock:
 
        scst_unregister_session(new_sess->scst_sess, 1, NULL);
        new_sess->scst_sess = NULL;
-       new_sess->deleted_from_session_list = 1; /* it wasn't added, actually */
-       session_free(new_sess);
+
+       mutex_lock(&target->target_mutex);
+       session_free(new_sess, false);
+       mutex_unlock(&target->target_mutex);
        goto out;
 }
 
 /* target_mutex supposed to be locked */
-int session_free(struct iscsi_session *session)
+int session_free(struct iscsi_session *session, bool del)
 {
        unsigned int i;
 
@@ -236,8 +238,6 @@ int session_free(struct iscsi_session *session)
        for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++)
                sBUG_ON(!list_empty(&session->cmnd_hash[i]));
 
-       sBUG_ON(session->scst_sess != NULL);
-
        if (session->sess_reinst_successor != NULL)
                sess_enable_reinstated_sess(session->sess_reinst_successor);
 
@@ -253,7 +253,19 @@ int session_free(struct iscsi_session *session)
                }
        }
 
-       if (!session->deleted_from_session_list)
+       if (session->scst_sess != NULL) {
+               /*
+                * We must NOT call scst_unregister_session() in the waiting
+                * mode, since we are under target_mutex. Otherwise we can
+                * establish a circular locking dependency between target_mutex
+                * and scst_mutex in SCST core (iscsi_report_aen() called by
+                * SCST core under scst_mutex).
+                */
+               scst_unregister_session(session->scst_sess, 0, NULL);
+               session->scst_sess = NULL;
+       }
+
+       if (del)
                list_del(&session->session_list_entry);
 
        kfree(session->initiator_name);
@@ -277,7 +289,7 @@ int session_del(struct iscsi_target *target, u64 sid)
                return -EBUSY;
        }
 
-       return session_free(session);
+       return session_free(session, true);
 }
 
 /* target_mutex supposed to be locked */
index 5cc166d..c24144b 100644 (file)
@@ -237,7 +237,8 @@ in/out in Makefile:
    commands reliably if they sent asynchronously to a stateful device.
    Turned off by default, turn it on if you use stateful device(s) and
    need as much error recovery reliability as possible. As a side
-   effect, no kernel patching is necessary.
+   effect, no kernel patching is necessary for pass-through device
+   handlers (scst_disk, etc.).
 
  - CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
    allowed to submit pass-through commands to real SCSI devices via the SCSI
@@ -319,7 +320,8 @@ entries:
     command:
 
       * "assign H:C:I:L HANDLER_NAME" assigns dev handler "HANDLER_NAME"
-        on device with host:channel:id:lun
+        on device with host:channel:id:lun. The recommended way to find out
+        H:C:I:L numbers is use of lsscsi utility.
 
   - "sessions" file, which lists currently connected initiators (open sessions)
 
@@ -420,10 +422,12 @@ following files and directories under /proc/scsi_tgt:
 
   - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds
     device with host:channel:id:lun with LUN "lun" in group "GROUP". Optionally,
-    the device could be marked as read only.
+    the device could be marked as read only. The recommended way to find out
+    H:C:I:L numbers is use of lsscsi utility.
 
   - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP/devices deletes device with
-    host:channel:id:lun from group "GROUP"
+    host:channel:id:lun from group "GROUP". The recommended way to find out
+    H:C:I:L numbers is use of lsscsi utility.
 
   - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds
     device with virtual name "V_NAME" with LUN "lun" in group "GROUP".
@@ -791,7 +795,8 @@ in the needed values using debug2perf root Makefile target.
    least 512KB or even more on all initiators and the target.
 
    You should also limit on all initiators maximum amount of sectors per
-   SCSI command. To do it on Linux initiators, run:
+   SCSI command. This tuning is also recommended on targets with large
+   read-ahead values. To do it on Linux, run:
 
    echo “64” > /sys/block/sdX/queue/max_sectors_kb
 
@@ -809,6 +814,9 @@ in the needed values using debug2perf root Makefile target.
    you changed the maximum amount of sectors per SCSI command for that
    device.
 
+   Note2: you need to restart SCST after you changed read-ahead settings
+   on the target.
+
  - You may need to increase amount of requests that OS on initiator
    sends to the target device. To do it on Linux initiators, run
 
@@ -820,7 +828,7 @@ in the needed values using debug2perf root Makefile target.
    directory, they also affect performance. If you find the best values,
    please share them with us.
 
- - On the target CFQ IO scheduler. In most cases it has performance
+ - On the target use CFQ IO scheduler. In most cases it has performance
    advantage over other IO schedulers, sometimes huge (2+ times
    aggregate throughput increase).
 
index 2ef50c9..eb525d5 100644 (file)
@@ -180,7 +180,8 @@ your favorit kernel configuration Makefile target, e.g. "make xconfig":
    commands reliably if they sent asynchronously to a stateful device.
    Turned off by default, turn it on if you use stateful device(s) and
    need as much error recovery reliability as possible. As a side
-   effect, no kernel patching is necessary.
+   effect, no kernel patching is necessary for pass-through device
+   handlers (scst_disk, etc.)
 
  - CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
    allowed to submit pass-through commands to real SCSI devices via the SCSI
@@ -260,7 +261,8 @@ entries:
     command:
 
       * "assign H:C:I:L HANDLER_NAME" assigns dev handler "HANDLER_NAME"
-        on device with host:channel:id:lun
+        on device with host:channel:id:lun. The recommended way to find out
+        H:C:I:L numbers is use of lsscsi utility.
 
   - "sessions" file, which lists currently connected initiators (open sessions)
 
@@ -360,10 +362,12 @@ following files and directories under /proc/scsi_tgt:
 
   - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds
     device with host:channel:id:lun with LUN "lun" in group "GROUP". Optionally,
-    the device could be marked as read only.
+    the device could be marked as read only. The recommended way to find out
+    H:C:I:L numbers is use of lsscsi utility.
 
   - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP/devices deletes device with
-    host:channel:id:lun from group "GROUP"
+    host:channel:id:lun from group "GROUP". The recommended way to find out
+    H:C:I:L numbers is use of lsscsi utility.
 
   - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds
     device with virtual name "V_NAME" with LUN "lun" in group "GROUP".
@@ -726,7 +730,8 @@ in the needed values using debug2perf root Makefile target.
    least 512KB or even more on all initiators and the target.
 
    You should also limit on all initiators maximum amount of sectors per
-   SCSI command. To do it on Linux initiators, run:
+   SCSI command. This tuning is also recommended on targets with large
+   read-ahead values. To do it on Linux, run:
 
    echo “64” > /sys/block/sdX/queue/max_sectors_kb
 
@@ -744,6 +749,9 @@ in the needed values using debug2perf root Makefile target.
    you changed the maximum amount of sectors per SCSI command for that
    device.
 
+   Note2: you need to restart SCST after you changed read-ahead settings
+   on the target.
+
  - You may need to increase amount of requests that OS on initiator
    sends to the target device. To do it on Linux initiators, run
 
@@ -755,7 +763,7 @@ in the needed values using debug2perf root Makefile target.
    directory, they also affect performance. If you find the best values,
    please share them with us.
 
- - On the target CFQ IO scheduler. In most cases it has performance
+ - On the target use CFQ IO scheduler. In most cases it has performance
    advantage over other IO schedulers, sometimes huge (2+ times
    aggregate throughput increase).
 
index 060f508..277c7f8 100644 (file)
@@ -1310,6 +1310,7 @@ struct scst_cmd {
        uint8_t driver_status;  /* set by mid-level */
 
        uint8_t *sense;         /* pointer to sense buffer */
+       unsigned short sense_bufflen; /* length of the sense buffer, if any */
 
        /* Used for storage of target driver private stuff */
        void *tgt_priv;
@@ -2002,6 +2003,12 @@ void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq);
  */
 void scst_set_busy(struct scst_cmd *cmd);
 
+/*
+ * Check if sense in the sense buffer, if any, in the correct format. If not,
+ * convert it to the correct format.
+ */
+void scst_check_convert_sense(struct scst_cmd *cmd);
+
 /*
  * Sets initial Unit Attention for sess, replacing default scst_sense_reset_UA
  */
@@ -2358,7 +2365,7 @@ static inline uint8_t *scst_cmd_get_sense_buffer(struct scst_cmd *cmd)
 /* Returns cmd's sense buffer length */
 static inline int scst_cmd_get_sense_buffer_len(struct scst_cmd *cmd)
 {
-       return SCST_SENSE_BUFFERSIZE;
+       return cmd->sense_bufflen;
 }
 
 /*
index 55cf904..172732b 100644 (file)
@@ -1376,8 +1376,7 @@ static int dev_user_process_reply_exec(struct scst_user_cmd *ucmd,
                        goto out_compl;
                res = copy_from_user(cmd->sense,
                        (void __user *)(unsigned long)ereply->psense_buffer,
-                       min((unsigned int)SCST_SENSE_BUFFERSIZE,
-                               (unsigned int)ereply->sense_len));
+                       min((int)cmd->sense_bufflen, (int)ereply->sense_len));
                if (res < 0) {
                        PRINT_ERROR("%s", "Unable to get sense data");
                        goto out_hwerr_res_set;
index 3ca5780..7dfb34a 100644 (file)
@@ -51,12 +51,12 @@ int debug_print_prefix(unsigned long trace_flag, const char *log_level,
 {
        int i = 0;
        unsigned long flags;
+       int pid = get_current_tid();
 
        spin_lock_irqsave(&trace_buf_lock, flags);
 
        if (trace_flag & TRACE_PID)
-               i += snprintf(&trace_buf[i], TRACE_BUF_SIZE, "[%d]: ",
-                             get_current_tid());
+               i += snprintf(&trace_buf[i], TRACE_BUF_SIZE, "[%d]: ", pid);
        if (prefix != NULL)
                i += snprintf(&trace_buf[i], TRACE_BUF_SIZE - i, "%s: ",
                              prefix);
index f01b056..cfddd3e 100644 (file)
@@ -77,6 +77,7 @@ int scst_alloc_sense(struct scst_cmd *cmd, int atomic)
        }
 
 memzero:
+       cmd->sense_bufflen = SCST_SENSE_BUFFERSIZE;
        memset(cmd->sense, 0, SCST_SENSE_BUFFERSIZE);
 
 out:
@@ -98,8 +99,8 @@ int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic,
                goto out;
        }
 
-       memcpy(cmd->sense, sense, min((int)len, (int)SCST_SENSE_BUFFERSIZE));
-       TRACE_BUFFER("Sense set", cmd->sense, SCST_SENSE_BUFFERSIZE);
+       memcpy(cmd->sense, sense, min((int)len, (int)cmd->sense_bufflen));
+       TRACE_BUFFER("Sense set", cmd->sense, cmd->sense_bufflen);
 
 out:
        TRACE_EXIT_RES(res);
@@ -143,9 +144,9 @@ void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq)
                goto out;
        }
 
-       scst_set_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
+       scst_set_sense(cmd->sense, cmd->sense_bufflen,
                scst_get_cmd_dev_d_sense(cmd), key, asc, ascq);
-       TRACE_BUFFER("Sense set", cmd->sense, SCST_SENSE_BUFFERSIZE);
+       TRACE_BUFFER("Sense set", cmd->sense, cmd->sense_bufflen);
 
 out:
        TRACE_EXIT();
@@ -162,7 +163,6 @@ void scst_set_sense(uint8_t *buffer, int len, bool d_sense,
 
        if (d_sense) {
                /* Descriptor format */
-
                if (len < 4) {
                        PRINT_ERROR("Length %d of sense buffer too small to "
                                "fit sense %x:%x:%x", len, key, asc, ascq);
@@ -177,7 +177,6 @@ void scst_set_sense(uint8_t *buffer, int len, bool d_sense,
                        buffer[3] = ascq;       /* ASCQ                 */
        } else {
                /* Fixed format */
-
                if (len < 14) {
                        PRINT_ERROR("Length %d of sense buffer too small to "
                                "fit sense %x:%x:%x", len, key, asc, ascq);
@@ -204,13 +203,16 @@ bool scst_analyze_sense(const uint8_t *sense, int len, unsigned int valid_mask,
 {
        bool res = false;
 
-       if (len < 14)
-               goto out;
-
        /* Response Code */
        if ((sense[0] == 0x70) || (sense[0] == 0x71)) {
                /* Fixed format */
 
+               if (len < 14) {
+                       PRINT_ERROR("Sense too small to analyze (%d, "
+                               "type fixed)", len);
+                       goto out;
+               }
+
                /* Sense Key */
                if ((valid_mask & SCST_SENSE_KEY_VALID) && (sense[2] != key))
                        goto out;
@@ -225,6 +227,12 @@ bool scst_analyze_sense(const uint8_t *sense, int len, unsigned int valid_mask,
        } else if ((sense[0] == 0x72) || (sense[0] == 0x73)) {
                /* Descriptor format */
 
+               if (len < 4) {
+                       PRINT_ERROR("Sense too small to analyze (%d, "
+                               "type descriptor)", len);
+                       goto out;
+               }
+
                /* Sense Key */
                if ((valid_mask & SCST_SENSE_KEY_VALID) && (sense[1] != key))
                        goto out;
@@ -247,6 +255,45 @@ out:
 }
 EXPORT_SYMBOL(scst_analyze_sense);
 
+void scst_check_convert_sense(struct scst_cmd *cmd)
+{
+       bool d_sense;
+
+       TRACE_ENTRY();
+
+       if ((cmd->sense == NULL) || (cmd->status != SAM_STAT_CHECK_CONDITION))
+               goto out;
+
+       d_sense = scst_get_cmd_dev_d_sense(cmd);
+       if (d_sense && ((cmd->sense[0] == 0x70) || (cmd->sense[0] == 0x71))) {
+               TRACE_MGMT_DBG("Converting fixed sense to descriptor (cmd %p)",
+                       cmd);
+               if (cmd->sense_bufflen < 14) {
+                       PRINT_ERROR("Sense too small to convert (%d, "
+                               "type fixed)", cmd->sense_bufflen);
+                       goto out;
+               }
+               scst_set_sense(cmd->sense, cmd->sense_bufflen, d_sense,
+                       cmd->sense[2], cmd->sense[12], cmd->sense[13]);
+       } else if (!d_sense && ((cmd->sense[0] == 0x72) ||
+                               (cmd->sense[0] == 0x73))) {
+               TRACE_MGMT_DBG("Converting descriptor sense to fixed (cmd %p)",
+                       cmd);
+               if (cmd->sense_bufflen < 4) {
+                       PRINT_ERROR("Sense too small to convert (%d, "
+                               "type descryptor)", cmd->sense_bufflen);
+                       goto out;
+               }
+               scst_set_sense(cmd->sense, cmd->sense_bufflen, d_sense,
+                       cmd->sense[1], cmd->sense[2], cmd->sense[3]);
+       }
+
+out:
+       TRACE_EXIT();
+       return;
+}
+EXPORT_SYMBOL(scst_check_convert_sense);
+
 static void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
        unsigned int len)
 {
@@ -468,12 +515,15 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
        TRACE_MGMT_DBG("Queuing REPORTED LUNS DATA CHANGED UA "
                "(sess %p)", sess);
 
+       local_bh_disable();
+
        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) {
-                       spin_lock_bh(&tgt_dev->tgt_dev_lock);
+                       spin_lock_nested(&tgt_dev->tgt_dev_lock,
+                               tgt_dev->lun);
                }
        }
 
@@ -501,10 +551,12 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
 
                list_for_each_entry_reverse(tgt_dev,
                                shead, sess_tgt_dev_list_entry) {
-                       spin_unlock_bh(&tgt_dev->tgt_dev_lock);
+                       spin_unlock(&tgt_dev->tgt_dev_lock);
                }
        }
 
+       local_bh_enable();
+
        TRACE_EXIT();
        return;
 }
@@ -699,8 +751,14 @@ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd)
 
        cmd->state = scst_get_cmd_abnormal_done_state(cmd);
 
-       EXTRACHECKS_BUG_ON((cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
-                          (cmd->tgt_dev == NULL));
+#ifdef CONFIG_SCST_EXTRACHECKS
+       if ((cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
+                  (cmd->tgt_dev == NULL) && !cmd->internal) {
+               PRINT_CRIT_ERROR("Wrong not inited cmd state %d (cmd %p, "
+                       "op %x)", cmd->state, cmd, cmd->cdb[0]);
+               sBUG();
+       }
+#endif
 
        TRACE_EXIT();
        return;
@@ -1541,6 +1599,7 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
                goto out_error;
 
        memcpy(rs_cmd->cdb, request_sense, sizeof(request_sense));
+       rs_cmd->cdb[1] |= scst_get_cmd_dev_d_sense(orig_cmd);
        rs_cmd->cdb_len = sizeof(request_sense);
        rs_cmd->data_direction = SCST_DATA_READ;
        rs_cmd->expected_data_direction = rs_cmd->data_direction;
@@ -3434,6 +3493,7 @@ again:
                spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock);
 
                mutex_lock(&scst_mutex);
+               local_bh_disable();
 
                for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
                        struct list_head *sess_tgt_dev_list_head =
@@ -3441,7 +3501,8 @@ again:
                        struct scst_tgt_dev *tgt_dev;
                        list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
                                        sess_tgt_dev_list_entry) {
-                               spin_lock_bh(&tgt_dev->tgt_dev_lock);
+                               spin_lock_nested(&tgt_dev->tgt_dev_lock,
+                                       tgt_dev->lun);
                        }
                }
 
@@ -3503,6 +3564,7 @@ out_unlock:
                        }
                }
 
+               local_bh_enable();
                mutex_unlock(&scst_mutex);
 
                spin_lock_bh(&cmd->tgt_dev->tgt_dev_lock);
index cc75fdb..cffc46e 100644 (file)
@@ -477,7 +477,7 @@ static inline void scst_dec_on_dev_cmd(struct scst_cmd *cmd)
 static inline void __scst_get(int barrier)
 {
        atomic_inc(&scst_cmd_count);
-       TRACE_DBG("Incrementing scst_cmd_count(%d)",
+       TRACE_DBG("Incrementing scst_cmd_count(new value %d)",
                atomic_read(&scst_cmd_count));
 
        /* See comment about smp_mb() in scst_suspend_activity() */
@@ -494,7 +494,7 @@ static inline void __scst_put(void)
                TRACE_MGMT_DBG("%s", "Waking up scst_dev_cmd_waitQ");
                wake_up_all(&scst_dev_cmd_waitQ);
        }
-       TRACE_DBG("Decrementing scst_cmd_count(%d)",
+       TRACE_DBG("Decrementing scst_cmd_count(new value %d)",
              atomic_read(&scst_cmd_count));
 }
 
@@ -503,10 +503,14 @@ void scst_sched_session_free(struct scst_session *sess);
 static inline void scst_sess_get(struct scst_session *sess)
 {
        atomic_inc(&sess->refcnt);
+       TRACE_DBG("Incrementing sess %p refcnt (new value %d)",
+               sess, atomic_read(&sess->refcnt));
 }
 
 static inline void scst_sess_put(struct scst_session *sess)
 {
+       TRACE_DBG("Decrementing sess %p refcnt (new value %d)",
+               sess, atomic_read(&sess->refcnt)-1);
        if (atomic_dec_and_test(&sess->refcnt))
                scst_sched_session_free(sess);
 }
@@ -514,10 +518,14 @@ static inline void scst_sess_put(struct scst_session *sess)
 static inline void __scst_cmd_get(struct scst_cmd *cmd)
 {
        atomic_inc(&cmd->cmd_ref);
+       TRACE_DBG("Incrementing cmd %p ref (new value %d)",
+               cmd, atomic_read(&cmd->cmd_ref));
 }
 
 static inline void __scst_cmd_put(struct scst_cmd *cmd)
 {
+       TRACE_DBG("Decrementing cmd %p ref (new value %d)",
+               cmd, atomic_read(&cmd->cmd_ref)-1);
        if (atomic_dec_and_test(&cmd->cmd_ref))
                scst_free_cmd(cmd);
 }
index 712df0a..e43602e 100644 (file)
@@ -127,8 +127,10 @@ static int scst_init_cmd(struct scst_cmd *cmd, enum scst_exec_context *context)
        rc = __scst_init_cmd(cmd);
        if (unlikely(rc > 0))
                goto out_redirect;
-       else if (unlikely(rc != 0))
+       else if (unlikely(rc != 0)) {
+               res = 1;
                goto out;
+       }
 
        /* Small context optimization */
        if (((*context == SCST_CONTEXT_TASKLET) ||
@@ -159,6 +161,7 @@ out_redirect:
                sBUG_ON(*context != SCST_CONTEXT_DIRECT);
                scst_set_busy(cmd);
                scst_set_cmd_abnormal_done_state(cmd);
+               res = 1;
                /* Keep initiator away from too many BUSY commands */
                msleep(50);
        } else {
@@ -284,14 +287,21 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
                goto active;
        }
 
+       /* 
+        * Cmd must be inited here to preserve the order. In case if cmd
+        * already preliminary completed by target driver we need to init
+        * cmd anyway to find out in which format we should return sense.
+        */
        cmd->state = SCST_CMD_STATE_INIT;
-       /* cmd must be inited here to preserve the order */
        rc = scst_init_cmd(cmd, &pref_context);
        if (unlikely(rc < 0))
                goto out;
-
-       if (unlikely(cmd->status != SAM_STAT_GOOD))
-               scst_set_cmd_abnormal_done_state(cmd);
+       else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION)) {
+               if (rc == 0) {
+                       /* Target driver preliminary completed cmd */
+                       scst_set_cmd_abnormal_done_state(cmd);
+               }
+       }
 
 active:
        /* Here cmd must not be in any cmd list, no locks */
@@ -1396,7 +1406,7 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state,
 
 static int scst_report_luns_local(struct scst_cmd *cmd)
 {
-       int rc;
+       int res = SCST_EXEC_COMPLETED, rc;
        int dev_cnt = 0;
        int buffer_size;
        int i;
@@ -1406,6 +1416,11 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
 
        TRACE_ENTRY();
 
+       if (scst_cmd_atomic(cmd)) {
+               res = SCST_EXEC_NEED_THREAD;
+               goto out;
+       }
+
        rc = scst_check_local_events(cmd);
        if (unlikely(rc != 0))
                goto out_done;
@@ -1528,8 +1543,9 @@ out_done:
        /* Report the result */
        cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
 
-       TRACE_EXIT();
-       return SCST_EXEC_COMPLETED;
+out:
+       TRACE_EXIT_RES(res);
+       return res;
 
 out_put_err:
        scst_put_buf(cmd, buffer);
@@ -2316,12 +2332,11 @@ static int scst_check_sense(struct scst_cmd *cmd)
        if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) &&
            SCST_SENSE_VALID(cmd->sense)) {
                PRINT_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense,
-                       SCST_SENSE_BUFFERSIZE);
+                       cmd->sense_bufflen);
 
                /* Check Unit Attention Sense Key */
                if (scst_is_ua_sense(cmd->sense)) {
-                       if (scst_analyze_sense(cmd->sense,
-                                       SCST_SENSE_BUFFERSIZE,
+                       if (scst_analyze_sense(cmd->sense, cmd->sense_bufflen,
                                        SCST_SENSE_ASC_VALID,
                                        0, SCST_SENSE_ASC_UA_RESET, 0)) {
                                if (cmd->double_ua_possible) {
@@ -2355,7 +2370,7 @@ static int scst_check_sense(struct scst_cmd *cmd)
                                }
                        }
                        scst_dev_check_set_UA(dev, cmd, cmd->sense,
-                               SCST_SENSE_BUFFERSIZE);
+                               cmd->sense_bufflen);
                }
        }
 
@@ -2529,7 +2544,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
                                        (long long unsigned int)cmd->lun,
                                        cmd->status);
                                PRINT_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense,
-                                       SCST_SENSE_BUFFERSIZE);
+                                       cmd->sense_bufflen);
 
                                /* Clearing the reservation */
                                spin_lock_bh(&dev->dev_lock);
@@ -2549,7 +2564,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
                    (cmd->status == SAM_STAT_CHECK_CONDITION) &&
                    SCST_SENSE_VALID(cmd->sense) &&
                    scst_is_ua_sense(cmd->sense) &&
-                   scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
+                   scst_analyze_sense(cmd->sense, cmd->sense_bufflen,
                                        SCST_SENSE_ASCx_VALID,
                                        0, 0x2a, 0x01)) {
                        TRACE(TRACE_SCSI, "MODE PARAMETERS CHANGED UA (lun "
@@ -2614,17 +2629,17 @@ static int scst_mode_select_checks(struct scst_cmd *cmd)
                    SCST_SENSE_VALID(cmd->sense) &&
                    scst_is_ua_sense(cmd->sense) &&
                     /* mode parameters changed */
-                   (scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
+                   (scst_analyze_sense(cmd->sense, cmd->sense_bufflen,
                                        SCST_SENSE_ASCx_VALID,
                                        0, 0x2a, 0x01) ||
-                    scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
+                    scst_analyze_sense(cmd->sense, cmd->sense_bufflen,
                                        SCST_SENSE_ASC_VALID,
                                        0, 0x29, 0) /* reset */ ||
-                    scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
+                    scst_analyze_sense(cmd->sense, cmd->sense_bufflen,
                                        SCST_SENSE_ASC_VALID,
                                        0, 0x28, 0) /* medium changed */ ||
                     /* cleared by another ini (just in case) */
-                    scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
+                    scst_analyze_sense(cmd->sense, cmd->sense_bufflen,
                                        SCST_SENSE_ASC_VALID,
                                        0, 0x2F, 0))) {
                if (atomic) {
@@ -3002,8 +3017,7 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
                        TRACE_MGMT_DBG("Requeuing UA for delivery failed cmd "
                                "%p", cmd);
                        scst_check_set_UA(cmd->tgt_dev, cmd->sense,
-                                       SCST_SENSE_BUFFERSIZE,
-                                       SCST_SET_UA_FLAG_AT_HEAD);
+                               cmd->sense_bufflen, SCST_SET_UA_FLAG_AT_HEAD);
                }
        }