- BLOCKIO made async

- Docs updates

- Debug logging improvements


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@101 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-03-02 16:29:36 +00:00
parent 5b4909133d
commit 8e69f4349a
8 changed files with 219 additions and 226 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
Summary of changes between versions 0.9.5 and 0.9.6
---------------------------------------------------
- FILEIO was renamed to VDISK. BLOCK IO added to it, thanks to Ross S. W.
- FILEIO was renamed to VDISK. BLOCKIO added to it, thanks to Ross S. W.
Walker and Vu Pham.
- Internal locking and execution context were reimplemnted. Particularly,
+23 -17
View File
@@ -108,10 +108,11 @@ block devices comparing to sending SCSI commands directly to SCSI
mid-level via scsi_do_req()/scsi_execute_async() has advantage that data
are transfered via system cache, so it is possible to fully benefit from
caching and read ahead performed by Linux's VM subsystem. The only
disadvantage here that there is superfluous data copying between the
cache and SCST's buffers. This issue is going to be addressed in the
next release. Virtual CDROM's are useful for remote installation. See
below for details how to setup and use VDISK device handler.
disadvantage here that in the FILEIO mode there is superfluous data
copying between the cache and SCST's buffers. This issue is going to be
addressed in the next release. Virtual CDROM's are useful for remote
installation. See below for details how to setup and use VDISK device
handler.
"Performance" device handlers for disks, MO disks and tapes in their
exec() method skip (pretend to execute) all READ and WRITE operations
@@ -351,8 +352,8 @@ subdirectories "vdisk" and "vcdrom". They have similar layout:
For example, "echo "open disk1 /vdisks/disk1" >/proc/scsi_tgt/vdisk/vdisk"
will open file /vdisks/disk1 as virtual VDISK disk with name "disk1".
IMPORTANT: By default for performance reasons VDISK devices use write back
========= caching policy. This is generally safe from the consistence of
IMPORTANT: By default for performance reasons VDISK FILEIO devices use write
========= back caching policy. This is generally safe from the consistence of
journaled file systems, laying over them, point of view, but
your unsaved cached data will be lost in case of
power/hardware/software failure, so you must supply your
@@ -389,8 +390,8 @@ IMPORTANT: Many disk and partition table management utilities don't support
first access to it from the remote initiator with another
block size.
BLOCKIO VDISK mode (written by Ross S. W. Walker)
-------------------------------------------------
BLOCKIO VDISK mode
------------------
This module works best for these types of scenarios:
@@ -411,20 +412,25 @@ non-discriminate caching.
have a consistent view of the primary targets in order to preserve data
integrity which a page cache backed IO type might not provide reliably.
Also it has an advantage over FILEIO that it doesn't copy data between
the system cache and the commands data buffers, so it saves a
considerable amount of CPU power and memory bandwidth.
Performance
-----------
Before doing any performance measurements note that:
I. Currently maximum performance is possible only with real SCSI devices
with several simultaneously executed commands (SCSI tagged queuing) or
performance handlers. If you have enough CPU power, VDISK handler also
could provide the same results, when aggregate throughput is close to
the aggregate throughput locally on the target from the same disks. Also
note, that currently IO subsystem in Linux implemented on such way, so a
VDISK device over a single file occupied entire formatted with some
file system device (eg /dev/hdc) could perform considerably better, than
a VDISK device over /dev/hdc itself without the file system involved.
or VDISK BLOCKIO mode with several simultaneously executed commands
(SCSI tagged queuing) or performance handlers. If you have enough CPU
power, VDISK FILEIO handler also could provide the same results, when
aggregate throughput is close to the aggregate throughput locally on the
target from the same disks. Also note, that currently IO subsystem in
Linux implemented on such way, so a VDISK FILEIO device over a single
file occupied entire formatted with some file system device (eg
/dev/hdc) could perform considerably better, than a VDISK FILEIO device
over /dev/hdc itself without the file system involved.
II. In order to get the maximum performance you should:
@@ -473,7 +479,7 @@ IMPORTANT: Some of those options enabled by default, i.e. SCST is optimized
expected.
IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
========= you can't get good write performance for VDISK devices with
========= you can't get good write performance for VDISK FILEIO devices with
default 512 bytes block sizes. You could get about 10% of the
expected one. This is because of "unusual" write access
pattern, with which Windows'es write data and which is
-4
View File
@@ -20,10 +20,6 @@ To be done
- Move linear searches to hash-table based.
- Create dev handler for block devices, which would insert commands as
block requests in the device's block queue, so they would processed
by IO-scheduler then.
- Redone some semaphores with completion interface.
- HIGHMEM cleanup. Looks like HIGHMEM usage doesn't worth the effort and
+16 -16
View File
@@ -665,9 +665,10 @@ static int vdisk_do_job(struct scst_cmd *cmd)
case READ_10:
case READ_12:
case READ_16:
if (virt_dev->blockio)
if (virt_dev->blockio) {
blockio_exec_rw(cmd, thr, lba_start, 0);
else
goto out;
} else
vdisk_exec_read(cmd, thr, loff);
break;
case WRITE_6:
@@ -691,9 +692,10 @@ static int vdisk_do_job(struct scst_cmd *cmd)
if (vdisk_fsync(thr, 0, 0, cmd) != 0)
goto done;
}
if (virt_dev->blockio)
if (virt_dev->blockio) {
blockio_exec_rw(cmd, thr, lba_start, 1);
else
goto out;
} else
vdisk_exec_write(cmd, thr, loff);
/* O_SYNC flag is used for WT devices */
if (do_fsync || fua)
@@ -2060,7 +2062,6 @@ out:
struct blockio_work {
atomic_t bios_inflight;
struct scst_cmd *cmd;
struct completion complete;
};
static int blockio_endio(struct bio *bio, unsigned int bytes_done, int error)
@@ -2089,8 +2090,12 @@ static int blockio_endio(struct bio *bio, unsigned int bytes_done, int error)
}
/* Decrement the bios in processing, and if zero signal completion */
if (atomic_dec_and_test(&blockio_work->bios_inflight))
complete(&blockio_work->complete);
if (atomic_dec_and_test(&blockio_work->bios_inflight)) {
blockio_work->cmd->completed = 1;
blockio_work->cmd->scst_cmd_done(blockio_work->cmd,
SCST_CMD_STATE_DEFAULT);
kfree(blockio_work);
}
bio_put(bio);
return 0;
@@ -2107,6 +2112,7 @@ static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
int need_new_bio;
struct scatterlist *sgl = cmd->sg;
struct blockio_work *blockio_work;
int bios = 0;
TRACE_ENTRY();
@@ -2117,10 +2123,8 @@ static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
blockio_work = kmalloc(sizeof (*blockio_work), GFP_KERNEL);
if (blockio_work == NULL)
goto out_no_mem;
atomic_set(&blockio_work->bios_inflight, 0);
blockio_work->cmd = cmd;
init_completion(&blockio_work->complete);
if (q)
max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES);
@@ -2147,7 +2151,7 @@ static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
goto out_no_bio;
}
atomic_inc(&blockio_work->bios_inflight);
bios++;
need_new_bio = 0;
bio->bi_end_io = blockio_endio;
bio->bi_sector = lba_start <<
@@ -2180,22 +2184,18 @@ static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
lba_start += sgl[j].length >> virt_dev->block_shift;
}
atomic_set(&blockio_work->bios_inflight, bios);
while (hbio) {
bio = hbio;
hbio = hbio->bi_next;
bio->bi_next = NULL;
submit_bio(write, bio);
}
if (q && q->unplug_fn)
q->unplug_fn(q);
wait_for_completion(&blockio_work->complete);
kfree(blockio_work);
out:
TRACE_EXIT();
return;
-2
View File
@@ -601,7 +601,6 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
dev->virt_name = dev_name;
scst_suspend_activity();
if (down_interruptible(&scst_mutex) != 0) {
res = -EINTR;
goto out_free_dev;
@@ -715,7 +714,6 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
#endif
scst_suspend_activity();
if (down_interruptible(&scst_mutex) != 0) {
res = -EINTR;
goto out_err;
+5
View File
@@ -1193,6 +1193,11 @@ void scst_free_cmd(struct scst_cmd *cmd)
TRACE_ENTRY();
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("Freeing aborted cmd %p (scst_cmd_count %d)",
cmd, atomic_read(&scst_cmd_count));
}
sBUG_ON(cmd->blocking);
#if defined(EXTRACHECKS) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+6 -4
View File
@@ -195,6 +195,8 @@ static int strncasecmp(const char *s1, const char *s2, int n)
#if defined(DEBUG) || defined(TRACING)
static DECLARE_MUTEX(scst_log_mutex);
int scst_proc_log_entry_write(struct file *file, const char *buf,
unsigned long length, unsigned long *log_level,
unsigned long default_level, const struct scst_proc_log *tbl)
@@ -356,7 +358,7 @@ static int scst_proc_scsi_tgt_gen_write_log(struct file *file, const char __user
TRACE_ENTRY();
if (down_interruptible(&scst_proc_mutex) != 0) {
if (down_interruptible(&scst_log_mutex) != 0) {
res = -EINTR;
goto out;
}
@@ -364,7 +366,7 @@ static int scst_proc_scsi_tgt_gen_write_log(struct file *file, const char __user
res = scst_proc_log_entry_write(file, buf, length,
&trace_flag, SCST_DEFAULT_LOG_FLAGS, scst_proc_local_trace_tbl);
up(&scst_proc_mutex);
up(&scst_log_mutex);
out:
TRACE_EXIT_RES(res);
@@ -1882,14 +1884,14 @@ static int log_info_show(struct seq_file *seq, void *v)
TRACE_ENTRY();
if (down_interruptible(&scst_proc_mutex) != 0) {
if (down_interruptible(&scst_log_mutex) != 0) {
res = -EINTR;
goto out;
}
res = scst_proc_log_entry_read(seq, trace_flag, scst_proc_local_trace_tbl);
up(&scst_proc_mutex);
up(&scst_log_mutex);
out:
TRACE_EXIT_RES(res);
+168 -182
View File
@@ -144,7 +144,8 @@ out_redirect:
} else {
unsigned long flags;
spin_lock_irqsave(&scst_init_lock, flags);
TRACE_MGMT_DBG("Adding cmd %p to init cmd list", cmd);
TRACE_MGMT_DBG("Adding cmd %p to init cmd list (scst_cmd_count "
"%d)", cmd, atomic_read(&scst_cmd_count));
list_add_tail(&cmd->cmd_list_entry, &scst_init_cmd_list);
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))
scst_init_poll_cnt++;
@@ -974,161 +975,8 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context)
return;
}
/* No locks supposed to be held */
static void scst_check_sense(struct scst_cmd *cmd, const uint8_t *rq_sense,
int rq_sense_len, int *next_state)
{
int sense_valid;
struct scst_device *dev = cmd->dev;
int dbl_ua_possible, ua_sent = 0;
TRACE_ENTRY();
/* If we had a internal bus reset behind us, set the command error UA */
if ((dev->scsi_dev != NULL) &&
unlikely(cmd->host_status == DID_RESET) &&
scst_is_ua_command(cmd))
{
TRACE(TRACE_MGMT, "DID_RESET: was_reset=%d host_status=%x",
dev->scsi_dev->was_reset, cmd->host_status);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_reset_UA));
/* just in case */
cmd->ua_ignore = 0;
/* It looks like it is safe to clear was_reset here */
dev->scsi_dev->was_reset = 0;
smp_mb();
}
if (rq_sense != NULL) {
sense_valid = SCST_SENSE_VALID(rq_sense);
if (sense_valid) {
/*
* We checked that rq_sense_len < sizeof(cmd->sense_buffer)
* in init_scst()
*/
memcpy(cmd->sense_buffer, rq_sense, rq_sense_len);
memset(&cmd->sense_buffer[rq_sense_len], 0,
sizeof(cmd->sense_buffer) - rq_sense_len);
}
} else
sense_valid = SCST_SENSE_VALID(cmd->sense_buffer);
dbl_ua_possible = dev->dev_double_ua_possible;
TRACE_DBG("cmd %p dbl_ua_possible %d", cmd, dbl_ua_possible);
if (unlikely(dbl_ua_possible)) {
spin_lock_bh(&dev->dev_lock);
barrier(); /* to reread dev_double_ua_possible */
dbl_ua_possible = dev->dev_double_ua_possible;
if (dbl_ua_possible)
ua_sent = dev->dev_reset_ua_sent;
else
spin_unlock_bh(&dev->dev_lock);
}
if (sense_valid) {
TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer,
sizeof(cmd->sense_buffer));
/* Check Unit Attention Sense Key */
if (cmd->sense_buffer[2] == UNIT_ATTENTION) {
if (cmd->sense_buffer[12] == SCST_SENSE_ASC_UA_RESET) {
if (dbl_ua_possible)
{
if (ua_sent) {
TRACE(TRACE_MGMT, "%s",
"Double UA detected");
/* Do retry */
TRACE(TRACE_MGMT, "Retrying cmd %p "
"(tag %d)", cmd, cmd->tag);
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
memset(cmd->sense_buffer, 0,
sizeof(cmd->sense_buffer));
cmd->retry = 1;
*next_state = SCST_CMD_STATE_SEND_TO_MIDLEV;
/*
* Dev is still blocked by this cmd, so
* it's OK to clear SCST_DEV_SERIALIZED
* here.
*/
dev->dev_double_ua_possible = 0;
dev->dev_serialized = 0;
dev->dev_reset_ua_sent = 0;
goto out_unlock;
} else
dev->dev_reset_ua_sent = 1;
}
}
if (cmd->ua_ignore == 0) {
if (unlikely(dbl_ua_possible)) {
__scst_process_UA(dev, cmd,
cmd->sense_buffer,
sizeof(cmd->sense_buffer), 0);
} else {
scst_process_UA(dev, cmd,
cmd->sense_buffer,
sizeof(cmd->sense_buffer), 0);
}
}
}
}
if (unlikely(dbl_ua_possible)) {
if (ua_sent && scst_is_ua_command(cmd)) {
TRACE_MGMT_DBG("%s", "Clearing dbl_ua_possible flag");
dev->dev_double_ua_possible = 0;
dev->dev_serialized = 0;
dev->dev_reset_ua_sent = 0;
}
spin_unlock_bh(&dev->dev_lock);
}
out:
TRACE_EXIT();
return;
out_unlock:
spin_unlock_bh(&dev->dev_lock);
goto out;
}
static int scst_check_auto_sense(struct scst_cmd *cmd)
{
int res = 0;
TRACE_ENTRY();
if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) &&
(!SCST_SENSE_VALID(cmd->sense_buffer) ||
SCST_NO_SENSE(cmd->sense_buffer)))
{
TRACE(TRACE_SCSI|TRACE_MINOR, "CHECK_CONDITION, but no sense: "
"cmd->status=%x, cmd->msg_status=%x, "
"cmd->host_status=%x, cmd->driver_status=%x", cmd->status,
cmd->msg_status, cmd->host_status, cmd->driver_status);
res = 1;
} else if (unlikely(cmd->host_status)) {
if ((cmd->host_status == DID_REQUEUE) ||
(cmd->host_status == DID_IMM_RETRY) ||
(cmd->host_status == DID_SOFT_ERROR)) {
scst_set_busy(cmd);
} else {
TRACE(TRACE_SCSI|TRACE_MINOR, "Host status %x "
"received, returning HARDWARE ERROR instead",
cmd->host_status);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
}
}
TRACE_EXIT_RES(res);
return res;
}
static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
const uint8_t *rq_sense, int rq_sense_len, int resid,
int *next_state)
const uint8_t *rq_sense, int rq_sense_len, int resid)
{
unsigned char type;
@@ -1148,6 +996,14 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
scst_set_resp_data_len(cmd, cmd->resp_data_len - resid);
}
/*
* We checked that rq_sense_len < sizeof(cmd->sense_buffer)
* in init_scst()
*/
memcpy(cmd->sense_buffer, rq_sense, rq_sense_len);
memset(&cmd->sense_buffer[rq_sense_len], 0,
sizeof(cmd->sense_buffer) - rq_sense_len);
TRACE(TRACE_SCSI, "result=%x, cmd->status=%x, resid=%d, "
"cmd->msg_status=%x, cmd->host_status=%x, "
"cmd->driver_status=%x", result, cmd->status, resid,
@@ -1170,7 +1026,7 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
if (unlikely(length <= 0)) {
PRINT_ERROR_PR("%s: scst_get_buf_first() failed",
__func__);
goto next;
goto out;
}
if (length > 2 && cmd->cdb[0] == MODE_SENSE) {
address[2] |= 0x80; /* Write Protect*/
@@ -1181,9 +1037,7 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
scst_put_buf(cmd, address);
}
next:
scst_check_sense(cmd, rq_sense, rq_sense_len, next_state);
out:
TRACE_EXIT();
return;
}
@@ -1223,19 +1077,15 @@ static void scst_cmd_done(struct scsi_cmnd *scsi_cmd)
{
struct scsi_request *req = NULL;
struct scst_cmd *cmd;
int next_state;
TRACE_ENTRY();
WARN_ON(in_irq());
cmd = scst_get_cmd(scsi_cmd, &req);
if (cmd == NULL)
goto out;
next_state = SCST_CMD_STATE_DEV_DONE;
scst_do_cmd_done(cmd, req->sr_result, req->sr_sense_buffer,
sizeof(req->sr_sense_buffer), scsi_cmd->resid, &next_state);
sizeof(req->sr_sense_buffer), scsi_cmd->resid);
/* Clear out request structure */
req->sr_use_sg = 0;
@@ -1247,7 +1097,7 @@ static void scst_cmd_done(struct scsi_cmnd *scsi_cmd)
scst_release_request(cmd);
cmd->state = next_state;
cmd->state = SCST_CMD_STATE_DEV_DONE;
scst_proccess_redirect_cmd(cmd,
scst_optimize_post_exec_context(cmd, scst_get_context()), 0);
@@ -1260,21 +1110,16 @@ out:
static void scst_cmd_done(void *data, char *sense, int result, int resid)
{
struct scst_cmd *cmd;
int next_state;
TRACE_ENTRY();
WARN_ON(in_irq());
cmd = (struct scst_cmd *)data;
if (cmd == NULL)
goto out;
next_state = SCST_CMD_STATE_DEV_DONE;
scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, resid,
&next_state);
scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, resid);
cmd->state = next_state;
cmd->state = SCST_CMD_STATE_DEV_DONE;
scst_proccess_redirect_cmd(cmd,
scst_optimize_post_exec_context(cmd, scst_get_context()), 0);
@@ -1289,8 +1134,6 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
{
TRACE_ENTRY();
sBUG_ON(in_irq());
scst_dec_on_dev_cmd(cmd, 0);
if (next_state == SCST_CMD_STATE_DEFAULT)
@@ -1325,15 +1168,7 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
SCST_LOAD_SENSE(scst_sense_hardw_error));
next_state = SCST_CMD_STATE_DEV_DONE;
}
if (scst_check_auto_sense(cmd)) {
PRINT_ERROR_PR("CHECK_CONDITION, but no valid sense for "
"opcode %d", cmd->cdb[0]);
}
#endif
scst_check_sense(cmd, NULL, 0, &next_state);
cmd->state = next_state;
scst_proccess_redirect_cmd(cmd,
@@ -2052,6 +1887,147 @@ out:
return res;
}
/* No locks supposed to be held */
static int scst_check_sense(struct scst_cmd *cmd)
{
int res = 0;
int sense_valid;
struct scst_device *dev = cmd->dev;
int dbl_ua_possible, ua_sent = 0;
TRACE_ENTRY();
/* If we had a internal bus reset behind us, set the command error UA */
if ((dev->scsi_dev != NULL) &&
unlikely(cmd->host_status == DID_RESET) &&
scst_is_ua_command(cmd))
{
TRACE(TRACE_MGMT, "DID_RESET: was_reset=%d host_status=%x",
dev->scsi_dev->was_reset, cmd->host_status);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_reset_UA));
/* just in case */
cmd->ua_ignore = 0;
/* It looks like it is safe to clear was_reset here */
dev->scsi_dev->was_reset = 0;
smp_mb();
}
sense_valid = SCST_SENSE_VALID(cmd->sense_buffer);
dbl_ua_possible = dev->dev_double_ua_possible;
TRACE_DBG("cmd %p dbl_ua_possible %d", cmd, dbl_ua_possible);
if (unlikely(dbl_ua_possible)) {
spin_lock_bh(&dev->dev_lock);
barrier(); /* to reread dev_double_ua_possible */
dbl_ua_possible = dev->dev_double_ua_possible;
if (dbl_ua_possible)
ua_sent = dev->dev_reset_ua_sent;
else
spin_unlock_bh(&dev->dev_lock);
}
if (sense_valid) {
TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer,
sizeof(cmd->sense_buffer));
/* Check Unit Attention Sense Key */
if (cmd->sense_buffer[2] == UNIT_ATTENTION) {
if (cmd->sense_buffer[12] == SCST_SENSE_ASC_UA_RESET) {
if (dbl_ua_possible)
{
if (ua_sent) {
TRACE(TRACE_MGMT, "%s",
"Double UA detected");
/* Do retry */
TRACE(TRACE_MGMT, "Retrying cmd %p "
"(tag %d)", cmd, cmd->tag);
cmd->status = 0;
cmd->msg_status = 0;
cmd->host_status = DID_OK;
cmd->driver_status = 0;
memset(cmd->sense_buffer, 0,
sizeof(cmd->sense_buffer));
cmd->retry = 1;
cmd->state = SCST_CMD_STATE_SEND_TO_MIDLEV;
res = 1;
/*
* Dev is still blocked by this cmd, so
* it's OK to clear SCST_DEV_SERIALIZED
* here.
*/
dev->dev_double_ua_possible = 0;
dev->dev_serialized = 0;
dev->dev_reset_ua_sent = 0;
goto out_unlock;
} else
dev->dev_reset_ua_sent = 1;
}
}
if (cmd->ua_ignore == 0) {
if (unlikely(dbl_ua_possible)) {
__scst_process_UA(dev, cmd,
cmd->sense_buffer,
sizeof(cmd->sense_buffer), 0);
} else {
scst_process_UA(dev, cmd,
cmd->sense_buffer,
sizeof(cmd->sense_buffer), 0);
}
}
}
}
if (unlikely(dbl_ua_possible)) {
if (ua_sent && scst_is_ua_command(cmd)) {
TRACE_MGMT_DBG("%s", "Clearing dbl_ua_possible flag");
dev->dev_double_ua_possible = 0;
dev->dev_serialized = 0;
dev->dev_reset_ua_sent = 0;
}
spin_unlock_bh(&dev->dev_lock);
}
out:
TRACE_EXIT_RES(res);
return res;
out_unlock:
spin_unlock_bh(&dev->dev_lock);
goto out;
}
static int scst_check_auto_sense(struct scst_cmd *cmd)
{
int res = 0;
TRACE_ENTRY();
if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) &&
(!SCST_SENSE_VALID(cmd->sense_buffer) ||
SCST_NO_SENSE(cmd->sense_buffer)))
{
TRACE(TRACE_SCSI|TRACE_MINOR, "CHECK_CONDITION, but no sense: "
"cmd->status=%x, cmd->msg_status=%x, "
"cmd->host_status=%x, cmd->driver_status=%x", cmd->status,
cmd->msg_status, cmd->host_status, cmd->driver_status);
res = 1;
} else if (unlikely(cmd->host_status)) {
if ((cmd->host_status == DID_REQUEUE) ||
(cmd->host_status == DID_IMM_RETRY) ||
(cmd->host_status == DID_SOFT_ERROR)) {
scst_set_busy(cmd);
} else {
TRACE(TRACE_SCSI|TRACE_MINOR, "Host status %x "
"received, returning HARDWARE ERROR instead",
cmd->host_status);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
}
}
TRACE_EXIT_RES(res);
return res;
}
static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres)
{
int res = 0, rc;
@@ -2077,6 +2053,10 @@ static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres)
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
}
} else if (scst_check_sense(cmd)) {
*pres = SCST_CMD_STATE_RES_CONT_SAME;
res = 1;
goto out;
}
type = cmd->dev->handler->type;
@@ -2420,6 +2400,12 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
list_del(&cmd->search_cmd_list_entry);
spin_unlock_irq(&cmd->sess->sess_list_lock);
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("Aborted cmd %p finished (cmd_ref %d, "
"scst_cmd_count %d)", cmd, atomic_read(&cmd->cmd_ref),
atomic_read(&scst_cmd_count));
}
scst_cmd_put(cmd);
res = SCST_CMD_STATE_RES_CONT_NEXT;