mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-17 20:56:24 +00:00
- A bunch of minor, mostly stability related, fixes.
- Docs update git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@248 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+10
-1
@@ -102,7 +102,7 @@ should be: the target driver is responsible for handling targets and
|
||||
their parameters, SCST core is responsible for handling backstorage.
|
||||
|
||||
If you need to configure different LUs for different targets you should
|
||||
create for each target group "Default_target_name", where target name
|
||||
create for each target group "Default_target_name", where "target_name"
|
||||
means name of the target, for example:
|
||||
"Default_iqn.2007-05.com.example:storage.disk1.sys1.xyz", and add there
|
||||
all necessary LUNs. Check SCST README file for details.
|
||||
@@ -114,6 +114,15 @@ abort or reset messages, then try to reduce QueuedCommands parameter in
|
||||
iscsi-scstd.conf file for the corresponding target. See also SCST README
|
||||
file for more details about that issue.
|
||||
|
||||
Sometimes, when there are communication problems with initiator(s),
|
||||
shutting down iSCSI-SCST can take very long time, up to about 10
|
||||
minutes. This can happen, because iSCSI-SCST can't be shutdown before
|
||||
all already sent to TCP for initiator(s) data will be actually sent
|
||||
and/or released by TCP. In case of communication failures this can take
|
||||
up to TCP transmit timeout, which is about 10 minutes. In such cases
|
||||
using netstat utility you can see that there is/are connection(s) to
|
||||
initiator(s) with non-0 "Send-Q".
|
||||
|
||||
CAUTION: Working of target and initiator on the same host isn't
|
||||
======== supported. See SCST README file for details.
|
||||
|
||||
|
||||
@@ -109,23 +109,6 @@ case "$1" in
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
dump)
|
||||
DUMP=`tempfile -p iscsi-scstd`
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -ne 0 ]; then
|
||||
echo "Failed to create dump file $DUMP"
|
||||
exit 1
|
||||
fi
|
||||
iscsi-scst-adm --mode dump --all >$DUMP
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -ne 0 ]; then
|
||||
echo "Error dumping config from daemon"
|
||||
rm $DUMP
|
||||
exit 1
|
||||
fi
|
||||
mv -u $DUMP $CONFIG_FILE
|
||||
echo "Config dumped to $CONFIG_FILE"
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|status|dump}"
|
||||
exit 1
|
||||
|
||||
@@ -92,6 +92,8 @@ static inline u32 cmnd_read_size(struct iscsi_cmnd *cmnd)
|
||||
|
||||
static inline void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
EXTRACHECKS_BUG_ON(cmnd->data_waiting);
|
||||
|
||||
cmnd->scst_state = ISCSI_CMD_STATE_RESTARTED;
|
||||
scst_restart_cmd(cmnd->scst_cmd, SCST_PREPROCESS_STATUS_SUCCESS,
|
||||
SCST_CONTEXT_THREAD);
|
||||
@@ -166,6 +168,12 @@ void cmnd_free(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
TRACE_DBG("%p", cmnd);
|
||||
|
||||
if (unlikely(cmnd->tmfabort)) {
|
||||
TRACE_MGMT_DBG("Free aborted cmd %p (scst cmd %p, state %d, "
|
||||
"parent_req %p)", cmnd, cmnd->scst_cmd, cmnd->scst_state,
|
||||
cmnd->parent_req);
|
||||
}
|
||||
|
||||
/* Catch users from cmd_list or rsp_cmd_list */
|
||||
EXTRACHECKS_BUG_ON(atomic_read(&cmnd->ref_cnt) != 0);
|
||||
|
||||
@@ -221,12 +229,16 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
if (cmnd->scst_cmd) {
|
||||
switch(cmnd->scst_state) {
|
||||
case ISCSI_CMD_STATE_AFTER_PREPROC:
|
||||
{
|
||||
struct scst_cmd *scst_cmd = cmnd->scst_cmd;
|
||||
TRACE_DBG("cmd %p AFTER_PREPROC", cmnd);
|
||||
cmnd->scst_state = ISCSI_CMD_STATE_RESTARTED;
|
||||
scst_restart_cmd(cmnd->scst_cmd,
|
||||
cmnd->scst_cmd = NULL;
|
||||
scst_restart_cmd(scst_cmd,
|
||||
SCST_PREPROCESS_STATUS_ERROR_FATAL,
|
||||
SCST_CONTEXT_DIRECT);
|
||||
SCST_CONTEXT_THREAD);
|
||||
break;
|
||||
}
|
||||
case ISCSI_CMD_STATE_PROCESSED:
|
||||
TRACE_DBG("cmd %p PROCESSED", cmnd);
|
||||
scst_tgt_cmd_done(cmnd->scst_cmd);
|
||||
@@ -1300,7 +1312,8 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
|
||||
if (dir == SCST_DATA_WRITE) {
|
||||
req->is_unsolicited_data = !(req_hdr->flags & ISCSI_CMD_FINAL);
|
||||
req->r2t_length = be32_to_cpu(req_hdr->data_length) - req->pdu.datasize;
|
||||
req->data_waiting = 1;
|
||||
if (req->r2t_length > 0)
|
||||
req->data_waiting = 1;
|
||||
}
|
||||
req->target_task_tag = get_next_ttt(conn);
|
||||
req->sg = scst_cmd_get_sg(scst_cmd);
|
||||
|
||||
@@ -103,7 +103,7 @@ struct iscsi_session {
|
||||
u32 tm_sn;
|
||||
struct iscsi_cmnd *tm_rsp;
|
||||
|
||||
/* read only, if there are connection(s) */
|
||||
/* Read only, if there are connection(s) */
|
||||
struct iscsi_sess_param sess_param;
|
||||
|
||||
spinlock_t cmnd_hash_lock;
|
||||
@@ -113,7 +113,7 @@ struct iscsi_session {
|
||||
|
||||
struct list_head session_list_entry;
|
||||
|
||||
/* Bot don't need any protection */
|
||||
/* Both don't need any protection */
|
||||
char *initiator_name;
|
||||
u64 sid;
|
||||
};
|
||||
|
||||
@@ -183,6 +183,15 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
/* We want all our already send operations to complete */
|
||||
conn->sock->ops->shutdown(conn->sock, RCV_SHUTDOWN);
|
||||
|
||||
/*
|
||||
* We need to call scst_unregister_session() ASAP to make SCST start
|
||||
* stuck commands recovery.
|
||||
*
|
||||
* ToDo: this is incompatible with MC/S
|
||||
*/
|
||||
scst_unregister_session(session->scst_sess, 0, NULL);
|
||||
session->scst_sess = NULL;
|
||||
|
||||
if (conn->read_state != RX_INIT_BHS) {
|
||||
struct iscsi_cmnd *cmnd = conn->read_cmnd;
|
||||
conn->read_cmnd = NULL;
|
||||
@@ -295,7 +304,7 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
}
|
||||
|
||||
iscsi_make_conn_wr_active(conn);
|
||||
msleep(50);
|
||||
msleep(200);
|
||||
|
||||
TRACE_CONN_CLOSE("conn %p, conn_ref_cnt %d left, wr_state %d, "
|
||||
"exp_cmd_sn %u", conn, atomic_read(&conn->conn_ref_cnt),
|
||||
@@ -379,8 +388,8 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
mutex_lock(&target->target_mutex);
|
||||
conn_free(conn);
|
||||
if (list_empty(&session->conn_list))
|
||||
session_del(target, session->sid);
|
||||
/* ToDo: this is incompatible with MC/S */
|
||||
session_free(session);
|
||||
mutex_unlock(&target->target_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
|
||||
@@ -136,7 +136,8 @@ 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]));
|
||||
|
||||
scst_unregister_session(session->scst_sess, 1, NULL);
|
||||
if (session->scst_sess != NULL)
|
||||
scst_unregister_session(session->scst_sess, 1, NULL);
|
||||
|
||||
list_del(&session->session_list_entry);
|
||||
|
||||
|
||||
+23
-16
@@ -426,7 +426,11 @@ subdirectories "vdisk" and "vcdrom". They have similar layout:
|
||||
and "FLAGS" are valid only for disk VDISK. The block size must be
|
||||
power of 2 and >= 512 bytes. Default is 512. Possible flags:
|
||||
|
||||
- WRITE_THROUGH - write back caching disabled
|
||||
- WRITE_THROUGH - write back caching disabled. Note, this option
|
||||
has sense only if you also *manually* disable write-back cache
|
||||
in *all* your backstorage devices and make sure it's actually
|
||||
disabled, since many devices are known to lie about this mode to
|
||||
get better benchmark results.
|
||||
|
||||
- READ_ONLY - read only
|
||||
|
||||
@@ -439,20 +443,23 @@ subdirectories "vdisk" and "vcdrom". They have similar layout:
|
||||
way as "*_perf" handlers.
|
||||
|
||||
- NV_CACHE - enables "non-volatile cache" mode. In this mode it is
|
||||
assumed that the target has GOOD UPS and software/hardware bug
|
||||
free, i.e. all data from the target's cache are guaranteed
|
||||
sooner or later to go to the media, hence all data
|
||||
synchronization with media operations, like SYNCHRONIZE_CACHE,
|
||||
are ignored (BTW, so violating SCSI standard) in order to bring
|
||||
a bit more performance. Use with extreme caution, since in this
|
||||
mode after a crash of the target journaled file systems don't
|
||||
guarantee the consistency after journal recovery, therefore
|
||||
manual fsck MUST be ran. The main intent for it is to determine
|
||||
the performance impact caused by the cache synchronization.
|
||||
Note, that since usually the journal barrier protection (see
|
||||
"IMPORTANT" below) turned off, enabling NV_CACHE could change
|
||||
nothing, since no data synchronization with media operations
|
||||
will go from the initiator.
|
||||
assumed that the target has a GOOD UPS with ability to cleanly
|
||||
shutdown target in case of power failure and it is
|
||||
software/hardware bugs free, i.e. all data from the target's
|
||||
cache are guaranteed sooner or later to go to the media. Hence
|
||||
all data synchronization with media operations, like
|
||||
SYNCHRONIZE_CACHE, are ignored in order to bring more
|
||||
performance. Also in this mode target reports to initiators that
|
||||
the corresponding device has write-through cache to disable all
|
||||
write-back cache workarounds used by initiators. Use with
|
||||
extreme caution, since in this mode after a crash of the target
|
||||
journaled file systems don't guarantee the consistency after
|
||||
journal recovery, therefore manual fsck MUST be ran. Note, that
|
||||
since usually the journal barrier protection (see "IMPORTANT"
|
||||
note below) turned off, enabling NV_CACHE could change nothing
|
||||
from data protection point of view, since no data
|
||||
synchronization with media operations will go from the
|
||||
initiator. This option overrides WRITE_THROUGH.
|
||||
|
||||
- BLOCKIO - enables block mode, which will perform direct block
|
||||
IO with a block device, bypassing page-cache for all operations.
|
||||
@@ -503,7 +510,7 @@ IMPORTANT: By default for performance reasons VDISK FILEIO devices use write
|
||||
backstorage device and lost on power failure event. Thus,
|
||||
ever with write-through cache mode, you still need a good UPS
|
||||
to protect yourself from your data loss (note, data loss, not
|
||||
the file system integrity).
|
||||
the file system integrity corruption).
|
||||
|
||||
IMPORTANT: Some disk and partition table management utilities don't support
|
||||
========= block sizes >512 bytes, therefore make sure that your favorite one
|
||||
|
||||
+17
-7
@@ -1621,13 +1621,23 @@ struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic,
|
||||
* Parameter:
|
||||
* - sess - session
|
||||
*
|
||||
* Note: All outstanding commands will be finished regularly. After
|
||||
* scst_unregister_session() returned no new commands must be sent to
|
||||
* SCST via scst_rx_cmd(). Also, the caller must ensure that no
|
||||
* scst_rx_cmd() or scst_rx_mgmt_fn_*() is called in paralell with
|
||||
* scst_unregister_session().
|
||||
* Can be called before result_fn() of scst_register_session() called,
|
||||
* i.e. during the session registration/initialization.
|
||||
* Notes:
|
||||
*
|
||||
* - All outstanding commands will be finished regularly. After
|
||||
* scst_unregister_session() returned no new commands must be sent to
|
||||
* SCST via scst_rx_cmd().
|
||||
*
|
||||
* - The caller must ensure that no scst_rx_cmd() or scst_rx_mgmt_fn_*() is
|
||||
* called in paralell with scst_unregister_session().
|
||||
*
|
||||
* - Can be called before result_fn() of scst_register_session() called,
|
||||
* i.e. during the session registration/initialization.
|
||||
*
|
||||
* - It is highly recommended to call scst_unregister_session() as soon as it
|
||||
* gets clear that session will be unregistered and not to wait until all
|
||||
* related commands finished. This function provides the wait functionality,
|
||||
* but it also starts recovering stuck commands, if there are any.
|
||||
* Otherwise, your target driver could wait for those commands forever.
|
||||
*/
|
||||
void scst_unregister_session(struct scst_session *sess, int wait,
|
||||
void (*unreg_done_fn) (struct scst_session *sess));
|
||||
|
||||
@@ -148,8 +148,13 @@ int cdrom_attach(struct scst_device *dev)
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0)
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
"%d:%d:%d:%d", dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun);
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
out_free_buf:
|
||||
kfree(buffer);
|
||||
|
||||
@@ -96,8 +96,13 @@ int changer_attach(struct scst_device *dev)
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0)
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
"%d:%d:%d:%d", dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES(res);
|
||||
|
||||
@@ -220,8 +220,13 @@ int disk_attach(struct scst_device *dev)
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0)
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
"%d:%d:%d:%d", dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun);
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
out_free_buf:
|
||||
kfree(buffer);
|
||||
|
||||
@@ -235,8 +235,13 @@ int modisk_attach(struct scst_device *dev)
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0)
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
"%d:%d:%d:%d: %x", dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun, res);
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
out_free_buf:
|
||||
kfree(buffer);
|
||||
|
||||
@@ -96,8 +96,13 @@ int processor_attach(struct scst_device *dev)
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0)
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
"%d:%d:%d:%d", dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
|
||||
@@ -96,8 +96,13 @@ int raid_attach(struct scst_device *dev)
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0)
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
"%d:%d:%d:%d", dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
|
||||
@@ -223,8 +223,13 @@ int tape_attach(struct scst_device *dev)
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0)
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
"%d:%d:%d:%d", dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun);
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
out_free_buf:
|
||||
kfree(buffer);
|
||||
|
||||
@@ -351,7 +351,7 @@ static struct file *vdisk_open(const struct scst_vdisk_dev *virt_dev)
|
||||
open_flags |= O_RDWR;
|
||||
if (virt_dev->o_direct_flag)
|
||||
open_flags |= O_DIRECT;
|
||||
if (virt_dev->wt_flag)
|
||||
if (virt_dev->wt_flag && !virt_dev->nv_cache)
|
||||
open_flags |= O_SYNC;
|
||||
TRACE_DBG("Opening file %s, flags 0x%x", virt_dev->file_name, open_flags);
|
||||
fd = filp_open(virt_dev->file_name, O_LARGEFILE | open_flags, 0600);
|
||||
@@ -494,7 +494,7 @@ static int vdisk_attach(struct scst_device *dev)
|
||||
dev->dh_priv = virt_dev;
|
||||
|
||||
dev->tst = DEF_TST;
|
||||
if (virt_dev->wt_flag)
|
||||
if (virt_dev->wt_flag && !virt_dev->nv_cache)
|
||||
dev->queue_alg = DEF_QUEUE_ALG_WT;
|
||||
else
|
||||
dev->queue_alg = DEF_QUEUE_ALG;
|
||||
@@ -1313,7 +1313,7 @@ static int vdisk_caching_pg(unsigned char *p, int pcontrol,
|
||||
0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
memcpy(p, caching_pg, sizeof(caching_pg));
|
||||
p[2] |= !(virt_dev->wt_flag) ? WCE : 0;
|
||||
p[2] |= !(virt_dev->wt_flag || virt_dev->nv_cache) ? WCE : 0;
|
||||
if (1 == pcontrol)
|
||||
memset(p + 2, 0, sizeof(caching_pg) - 2);
|
||||
return sizeof(caching_pg);
|
||||
@@ -1344,7 +1344,7 @@ static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol,
|
||||
break;
|
||||
case 2:
|
||||
p[2] |= DEF_TST << 5;
|
||||
if (virt_dev->wt_flag)
|
||||
if (virt_dev->wt_flag || virt_dev->nv_cache)
|
||||
p[3] |= DEF_QUEUE_ALG_WT << 4;
|
||||
else
|
||||
p[3] |= DEF_QUEUE_ALG << 4;
|
||||
@@ -1529,7 +1529,7 @@ static int vdisk_set_wt(struct scst_vdisk_dev *virt_dev, int wt)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if ((virt_dev->wt_flag == wt) || virt_dev->nullio)
|
||||
if ((virt_dev->wt_flag == wt) || virt_dev->nullio || virt_dev->nv_cache)
|
||||
goto out;
|
||||
|
||||
spin_lock(&virt_dev->flags_lock);
|
||||
@@ -2486,7 +2486,7 @@ static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
||||
struct scst_vdisk_dev *virt_dev =
|
||||
(struct scst_vdisk_dev *)dev->dh_priv;
|
||||
dev->tst = DEF_TST;
|
||||
if (virt_dev->wt_flag)
|
||||
if (virt_dev->wt_flag && !virt_dev->nv_cache)
|
||||
dev->queue_alg = DEF_QUEUE_ALG_WT;
|
||||
else
|
||||
dev->queue_alg = DEF_QUEUE_ALG;
|
||||
|
||||
+15
-18
@@ -2296,7 +2296,11 @@ int scst_obtain_device_parameters(struct scst_device *dev)
|
||||
|
||||
goto out;
|
||||
} else {
|
||||
#if 0 /* 3ware controller is buggy and returns CONDITION_GOOD instead of CHECK_CONDITION */
|
||||
if ((status_byte(res) == CHECK_CONDITION) &&
|
||||
#else
|
||||
if (
|
||||
#endif
|
||||
SCST_SENSE_VALID(sense_buffer) &&
|
||||
(sense_buffer[2] == ILLEGAL_REQUEST)) {
|
||||
TRACE(TRACE_SCSI|TRACE_MGMT_MINOR, "Device %d:%d:%d:%d "
|
||||
@@ -3103,7 +3107,6 @@ static spinlock_t scst_tm_dbg_lock = SPIN_LOCK_UNLOCKED;
|
||||
/* All serialized by scst_tm_dbg_lock */
|
||||
struct
|
||||
{
|
||||
unsigned int tm_dbg_active:1;
|
||||
unsigned int tm_dbg_release:1;
|
||||
unsigned int tm_dbg_blocked:1;
|
||||
} tm_dbg_flags;
|
||||
@@ -3122,19 +3125,16 @@ void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
{
|
||||
if ((acg_dev->acg == scst_default_acg) && (acg_dev->lun == 0)) {
|
||||
unsigned long flags;
|
||||
/* Do TM debugging only for LUN 0 */
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
if (!tm_dbg_flags.tm_dbg_active) {
|
||||
/* Do TM debugging only for LUN 0 */
|
||||
tm_dbg_p_cmd_list_waitQ =
|
||||
&tgt_dev->dev->p_cmd_lists->cmd_list_waitQ;
|
||||
tm_dbg_state = INIT_TM_DBG_STATE;
|
||||
tm_dbg_on_state_passes =
|
||||
tm_dbg_on_state_num_passes[tm_dbg_state];
|
||||
__set_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags);
|
||||
PRINT_INFO("LUN 0 connected from initiator %s is under "
|
||||
"TM debugging", tgt_dev->sess->tgt->tgtt->name);
|
||||
tm_dbg_flags.tm_dbg_active = 1;
|
||||
}
|
||||
tm_dbg_p_cmd_list_waitQ =
|
||||
&tgt_dev->dev->p_cmd_lists->cmd_list_waitQ;
|
||||
tm_dbg_state = INIT_TM_DBG_STATE;
|
||||
tm_dbg_on_state_passes =
|
||||
tm_dbg_on_state_num_passes[tm_dbg_state];
|
||||
__set_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags);
|
||||
PRINT_INFO("LUN 0 connected from initiator %s is under "
|
||||
"TM debugging", tgt_dev->sess->tgt->tgtt->name);
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
}
|
||||
}
|
||||
@@ -3146,7 +3146,6 @@ void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
del_timer_sync(&tm_dbg_timer);
|
||||
spin_lock_irqsave(&scst_tm_dbg_lock, flags);
|
||||
tm_dbg_p_cmd_list_waitQ = NULL;
|
||||
tm_dbg_flags.tm_dbg_active = 0;
|
||||
spin_unlock_irqrestore(&scst_tm_dbg_lock, flags);
|
||||
}
|
||||
}
|
||||
@@ -3342,9 +3341,6 @@ void tm_dbg_task_mgmt(struct scst_device *dev, const char *fn, int force)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!tm_dbg_flags.tm_dbg_active)
|
||||
goto out;
|
||||
|
||||
if (dev != NULL) {
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
bool found = 0;
|
||||
@@ -3371,7 +3367,8 @@ void tm_dbg_task_mgmt(struct scst_device *dev, const char *fn, int force)
|
||||
tm_dbg_change_state();
|
||||
tm_dbg_flags.tm_dbg_release = 1;
|
||||
smp_mb();
|
||||
wake_up_all(tm_dbg_p_cmd_list_waitQ);
|
||||
if (tm_dbg_p_cmd_list_waitQ != NULL)
|
||||
wake_up_all(tm_dbg_p_cmd_list_waitQ);
|
||||
} else {
|
||||
TRACE_MGMT_DBG("%s: while OFFLINE state, doing nothing", fn);
|
||||
}
|
||||
|
||||
+53
-38
@@ -208,9 +208,16 @@ void scst_cmd_init_done(struct scst_cmd *cmd, int pref_context)
|
||||
|
||||
spin_lock_irqsave(&sess->sess_list_lock, flags);
|
||||
|
||||
list_add_tail(&cmd->search_cmd_list_entry, &sess->search_cmd_list);
|
||||
|
||||
if (unlikely(sess->init_phase != SCST_SESS_IPH_READY)) {
|
||||
/*
|
||||
* We have to always keep command in the search list from the
|
||||
* very beginning, because otherwise it can be missed during
|
||||
* TM processing. This check is needed because there might be
|
||||
* old, i.e. deferred, commands and new, i.e. just coming, ones.
|
||||
*/
|
||||
if (cmd->search_cmd_list_entry.next == NULL)
|
||||
list_add_tail(&cmd->search_cmd_list_entry,
|
||||
&sess->search_cmd_list);
|
||||
switch(sess->init_phase) {
|
||||
case SCST_SESS_IPH_SUCCESS:
|
||||
break;
|
||||
@@ -228,7 +235,8 @@ void scst_cmd_init_done(struct scst_cmd *cmd, int pref_context)
|
||||
default:
|
||||
sBUG();
|
||||
}
|
||||
}
|
||||
} else
|
||||
list_add_tail(&cmd->search_cmd_list_entry, &sess->search_cmd_list);
|
||||
|
||||
spin_unlock_irqrestore(&sess->sess_list_lock, flags);
|
||||
|
||||
@@ -1845,6 +1853,7 @@ static int scst_send_to_midlev(struct scst_cmd **active_cmd)
|
||||
struct scst_cmd *cmd = *active_cmd;
|
||||
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
|
||||
struct scst_device *dev = cmd->dev;
|
||||
struct scst_session *sess = cmd->sess;
|
||||
typeof(tgt_dev->expected_sn) expected_sn;
|
||||
int count;
|
||||
|
||||
@@ -1852,11 +1861,12 @@ static int scst_send_to_midlev(struct scst_cmd **active_cmd)
|
||||
|
||||
res = SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
|
||||
__scst_get(0); /* protect dev & tgt_dev */
|
||||
__scst_get(0); /* protect dev */
|
||||
scst_sess_get(sess); /* protect tgt_dev */
|
||||
|
||||
if (unlikely(cmd->internal || cmd->retry)) {
|
||||
rc = scst_do_send_to_midlev(cmd);
|
||||
/* !! At this point cmd, sess & tgt_dev can be already freed !! */
|
||||
/* !! At this point cmd can be already freed !! */
|
||||
if (rc == SCST_EXEC_NEED_THREAD) {
|
||||
TRACE_DBG("%s", "scst_do_send_to_midlev() requested "
|
||||
"thread context, rescheduling");
|
||||
@@ -1875,7 +1885,7 @@ static int scst_send_to_midlev(struct scst_cmd **active_cmd)
|
||||
getnstimeofday(&ts);
|
||||
cmd->pre_exec_finish = scst_sec_to_nsec(ts.tv_sec) + ts.tv_nsec;
|
||||
TRACE_DBG("cmd %p (sess %p): pre_exec_finish %Ld (tv_sec %ld, "
|
||||
"tv_nsec %ld)", cmd, cmd->sess, cmd->pre_exec_finish, ts.tv_sec,
|
||||
"tv_nsec %ld)", cmd, sess, cmd->pre_exec_finish, ts.tv_sec,
|
||||
ts.tv_nsec);
|
||||
}
|
||||
#endif
|
||||
@@ -1960,6 +1970,7 @@ out_unplug:
|
||||
generic_unplug_device(dev->scsi_dev->request_queue);
|
||||
|
||||
out_put:
|
||||
scst_sess_put(sess);
|
||||
__scst_put();
|
||||
/* !! At this point sess, dev and tgt_dev can be already freed !! */
|
||||
|
||||
@@ -2434,6 +2445,19 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
#ifdef DEBUG_TM
|
||||
if (cmd->tm_dbg_delayed && !test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
if (scst_cmd_atomic(cmd)) {
|
||||
TRACE_MGMT_DBG("%s", "DEBUG_TM delayed cmd needs a thread");
|
||||
res = SCST_CMD_STATE_RES_NEED_THREAD;
|
||||
return res;
|
||||
}
|
||||
TRACE_MGMT_DBG("Delaying cmd %p (tag %llu) for 1 second",
|
||||
cmd, cmd->tag);
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cmd->tgt_dev != NULL) {
|
||||
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
|
||||
scst_on_hq_cmd_response(cmd);
|
||||
@@ -2516,19 +2540,6 @@ static int scst_xmit_response(struct scst_cmd *cmd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TM
|
||||
if (cmd->tm_dbg_delayed && !test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
if (atomic && !cmd->tgtt->xmit_response_atomic) {
|
||||
TRACE_MGMT_DBG("%s", "DEBUG_TM delayed cmd needs a thread");
|
||||
res = SCST_CMD_STATE_RES_NEED_THREAD;
|
||||
goto out;
|
||||
}
|
||||
TRACE_MGMT_DBG("Delaying cmd %p (tag %llu) for 1 second",
|
||||
cmd, cmd->tag);
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
int finished_cmds = atomic_read(&cmd->sess->tgt->finished_cmds);
|
||||
|
||||
@@ -3439,12 +3450,12 @@ static int scst_set_mcmd_next_state(struct scst_mgmt_cmd *mcmd)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int __scst_check_unblock_aborted_cmd(struct scst_cmd *cmd)
|
||||
static bool __scst_check_unblock_aborted_cmd(struct scst_cmd *cmd,
|
||||
struct list_head *list_entry)
|
||||
{
|
||||
int res;
|
||||
bool res;
|
||||
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
TRACE_MGMT_DBG("Adding aborted blocked cmd %p to active cmd "
|
||||
"list", cmd);
|
||||
list_del(list_entry);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
@@ -3472,8 +3483,11 @@ static void scst_unblock_aborted_cmds(int scst_mutex_held)
|
||||
local_irq_disable();
|
||||
list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list,
|
||||
blocked_cmd_list_entry) {
|
||||
if (__scst_check_unblock_aborted_cmd(cmd))
|
||||
list_del(&cmd->blocked_cmd_list_entry);
|
||||
if (__scst_check_unblock_aborted_cmd(cmd,
|
||||
&cmd->blocked_cmd_list_entry)) {
|
||||
TRACE_MGMT_DBG("Unblock aborted blocked cmd %p",
|
||||
cmd);
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
@@ -3485,11 +3499,11 @@ static void scst_unblock_aborted_cmds(int scst_mutex_held)
|
||||
list_for_each_entry_safe(cmd, tcmd,
|
||||
&tgt_dev->deferred_cmd_list,
|
||||
sn_cmd_list_entry) {
|
||||
if (__scst_check_unblock_aborted_cmd(cmd)) {
|
||||
TRACE_MGMT_DBG("Deleting aborted SN "
|
||||
"cmd %p from SN list", cmd);
|
||||
if (__scst_check_unblock_aborted_cmd(cmd,
|
||||
&cmd->sn_cmd_list_entry)) {
|
||||
TRACE_MGMT_DBG("Unblockd aborted SN "
|
||||
"cmd %p", cmd);
|
||||
tgt_dev->def_cmd_count--;
|
||||
list_del(&cmd->sn_cmd_list_entry);
|
||||
}
|
||||
}
|
||||
spin_unlock(&tgt_dev->sn_lock);
|
||||
@@ -4105,6 +4119,9 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
|
||||
if (scst_is_strict_mgmt_fn(mcmd->fn) && (mcmd->completed_cmd_count > 0))
|
||||
mcmd->status = SCST_MGMT_STATUS_TASK_NOT_EXIST;
|
||||
|
||||
TRACE(TRACE_MGMT_MINOR, "TM command fn %d finished, status %x",
|
||||
mcmd->fn, mcmd->status);
|
||||
|
||||
if (mcmd->sess->tgt->tgtt->task_mgmt_fn_done) {
|
||||
TRACE_DBG("Calling target %s task_mgmt_fn_done()",
|
||||
mcmd->sess->tgt->tgtt->name);
|
||||
@@ -4557,7 +4574,6 @@ restart:
|
||||
TRACE_DBG("Deleting cmd %p from init deferred cmd list", cmd);
|
||||
list_del(&cmd->cmd_list_entry);
|
||||
atomic_dec(&sess->sess_cmd_count);
|
||||
list_del(&cmd->search_cmd_list_entry);
|
||||
spin_unlock_irq(&sess->sess_list_lock);
|
||||
scst_cmd_init_done(cmd, SCST_CONTEXT_THREAD);
|
||||
spin_lock_irq(&sess->sess_list_lock);
|
||||
@@ -4666,11 +4682,12 @@ void scst_unregister_session(struct scst_session *sess, int wait,
|
||||
sess->shutdown_compl = NULL;
|
||||
#endif
|
||||
|
||||
TRACE_DBG("Adding sess %p to scst_sess_shut_list", sess);
|
||||
list_add_tail(&sess->sess_shut_list_entry, &scst_sess_shut_list);
|
||||
|
||||
spin_unlock_irqrestore(&scst_mgmt_lock, flags);
|
||||
|
||||
tm_dbg_task_mgmt(NULL, "UNREGISTER SESSION", 1);
|
||||
|
||||
scst_sess_put(sess);
|
||||
wake_up(&scst_mgmt_waitQ);
|
||||
|
||||
if (wait) {
|
||||
TRACE_DBG("Waiting for session %p to complete", sess);
|
||||
@@ -4689,10 +4706,11 @@ static void scst_pre_unreg_sess(struct scst_session *sess)
|
||||
{
|
||||
int i;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
unsigned long flags;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tm_dbg_task_mgmt(NULL, "UNREGISTER SESSION", 1);
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
struct list_head *sess_tgt_dev_list_head =
|
||||
@@ -4713,10 +4731,7 @@ static void scst_pre_unreg_sess(struct scst_session *sess)
|
||||
|
||||
sess->shut_phase = SCST_SESS_SPH_SHUTDOWN;
|
||||
|
||||
spin_lock_irqsave(&scst_mgmt_lock, flags);
|
||||
TRACE_DBG("Adding sess %p to scst_sess_shut_list", sess);
|
||||
list_add_tail(&sess->sess_shut_list_entry, &scst_sess_shut_list);
|
||||
spin_unlock_irqrestore(&scst_mgmt_lock, flags);
|
||||
scst_sess_put(sess);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user