mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-17 02:31:27 +00:00
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
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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 *,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
20
scst/README
20
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).
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user