From fa191c256b8fa7f17fb3f4bbd9a01094b28abe84 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 9 Apr 2009 10:26:48 +0000 Subject: [PATCH] Merge of r764 git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/1.0.1.x@765 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/iscsi.c | 6 ++ iscsi-scst/kernel/iscsi.h | 3 +- iscsi-scst/kernel/nthread.c | 13 +--- iscsi-scst/kernel/session.c | 28 +++++-- scst/README | 20 +++-- scst/README_in-tree | 20 +++-- scst/include/scst.h | 9 ++- scst/src/dev_handlers/scst_user.c | 3 +- scst/src/scst_debug.c | 4 +- scst/src/scst_lib.c | 125 ++++++++++++++++++++++++------ scst/src/scst_priv.h | 12 ++- scst/src/scst_targ.c | 54 ++++++++----- 12 files changed, 216 insertions(+), 81 deletions(-) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 57f50a25c..9121456c9 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -2647,6 +2647,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) { diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 4255d61c0..8fb5a2b42 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -122,7 +122,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; @@ -456,7 +455,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 *, diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 5cb1c67d9..acc05d19d 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -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); diff --git a/iscsi-scst/kernel/session.c b/iscsi-scst/kernel/session.c index 2014975aa..8edac12a6 100644 --- a/iscsi-scst/kernel/session.c +++ b/iscsi-scst/kernel/session.c @@ -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 */ diff --git a/scst/README b/scst/README index 5cc166d4a..c24144bff 100644 --- a/scst/README +++ b/scst/README @@ -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). diff --git a/scst/README_in-tree b/scst/README_in-tree index 2ef50c9b0..eb525d5df 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -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). diff --git a/scst/include/scst.h b/scst/include/scst.h index 02f2fcb06..4f12fe1f5 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1302,6 +1302,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; @@ -1994,6 +1995,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 */ @@ -2303,7 +2310,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; } /* diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index a67f42134..954070526 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -1352,8 +1352,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; diff --git a/scst/src/scst_debug.c b/scst/src/scst_debug.c index 3ca57804e..7dfb34a23 100644 --- a/scst/src/scst_debug.c +++ b/scst/src/scst_debug.c @@ -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); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index a308ef66a..5313e9f11 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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(); @@ -156,23 +157,40 @@ EXPORT_SYMBOL(scst_set_cmd_error); void scst_set_sense(uint8_t *buffer, int len, bool d_sense, int key, int asc, int ascq) { - sBUG_ON(len < SCST_STANDARD_SENSE_LEN); + sBUG_ON(len == 0); memset(buffer, 0, len); if (d_sense) { /* Descriptor format */ - buffer[0] = 0x72; /* Response Code */ - buffer[1] = key; /* Sense Key */ - buffer[2] = asc; /* ASC */ - buffer[3] = ascq; /* ASCQ */ + if (len < 4) { + PRINT_ERROR("Length %d of sense buffer too small to " + "fit sense %x:%x:%x", len, key, asc, ascq); + } + + buffer[0] = 0x72; /* Response Code */ + if (len > 1) + buffer[1] = key; /* Sense Key */ + if (len > 2) + buffer[2] = asc; /* ASC */ + if (len > 3) + buffer[3] = ascq; /* ASCQ */ } else { /* Fixed format */ - buffer[0] = 0x70; /* Response Code */ - buffer[2] = key; /* Sense Key */ - buffer[7] = 0x0a; /* Additional Sense Length */ - buffer[12] = asc; /* ASC */ - buffer[13] = ascq; /* ASCQ */ + if (len < 14) { + PRINT_ERROR("Length %d of sense buffer too small to " + "fit sense %x:%x:%x", len, key, asc, ascq); + } + + buffer[0] = 0x70; /* Response Code */ + if (len > 2) + buffer[2] = key; /* Sense Key */ + if (len > 7) + buffer[7] = 0x0a; /* Additional Sense Length */ + if (len > 12) + buffer[12] = asc; /* ASC */ + if (len > 13) + buffer[13] = ascq; /* ASCQ */ } TRACE_BUFFER("Sense set", buffer, len); @@ -185,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; @@ -206,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; @@ -228,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) { @@ -449,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); } } @@ -482,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; } @@ -680,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; @@ -1522,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; @@ -3355,6 +3433,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 = @@ -3362,7 +3441,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); } } @@ -3424,6 +3504,7 @@ out_unlock: } } + local_bh_enable(); mutex_unlock(&scst_mutex); spin_lock_bh(&cmd->tgt_dev->tgt_dev_lock); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index cc75fdb64..cffc46eff 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -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); } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index b0e2fb694..ddd6e6999 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -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,11 +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; + 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 */ @@ -865,7 +878,8 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status, set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags); /* go through */ case SCST_PREPROCESS_STATUS_ERROR: - scst_set_cmd_error(cmd, + if (cmd->sense != NULL) + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); scst_set_cmd_abnormal_done_state(cmd); break; @@ -1392,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; @@ -1402,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; @@ -1524,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); @@ -2312,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) { @@ -2351,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); } } @@ -2525,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); @@ -2545,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 " @@ -2610,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) { @@ -2990,8 +3009,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); } }