- TM fixes

- Optimizations and send timeout introduced in r295 temporary disabled
 - Big connection shutdown times improvements. Great thanks to Alexey Kuznetsov for suggestions!
 - RESERVE/RELEASE serialization now made with TST field 0 (i.e. single task set)
 - Other minor fixes and improvements


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@297 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2008-02-29 18:25:56 +00:00
parent f17ee9c61b
commit ba3062fe6b
9 changed files with 178 additions and 72 deletions

View File

@@ -115,15 +115,6 @@ iscsi-scstd.conf file for the corresponding target to some lower value,
like 8 (default is 32). 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.

View File

@@ -1742,7 +1742,7 @@ static void execute_task_management(struct iscsi_cmnd *req)
struct iscsi_session *sess = conn->session;
struct iscsi_task_mgt_hdr *req_hdr =
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
int err = 0, function = req_hdr->function & ISCSI_FUNCTION_MASK;
int rc, status, function = req_hdr->function & ISCSI_FUNCTION_MASK;
struct scst_rx_mgmt_params params;
TRACE((function == ISCSI_FUNCTION_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
@@ -1754,13 +1754,20 @@ static void execute_task_management(struct iscsi_cmnd *req)
iscsi_extracheck_is_rd_thread(conn);
spin_lock(&sess->sn_lock);
sess->tm_active = 1;
sess->tm_active++;
sess->tm_sn = req_hdr->cmd_sn;
if (sess->tm_rsp != NULL) {
struct iscsi_cmnd *tm_rsp = sess->tm_rsp;
TRACE(TRACE_MGMT_MINOR, "Dropping delayed TM rsp %p", tm_rsp);
sess->tm_rsp = NULL;
sess->tm_active--;
spin_unlock(&sess->sn_lock);
sBUG_ON(sess->tm_active < 0);
rsp_cmnd_release(tm_rsp);
} else
spin_unlock(&sess->sn_lock);
@@ -1773,7 +1780,8 @@ static void execute_task_management(struct iscsi_cmnd *req)
(req_hdr->rtt != ISCSI_RESERVED_TAG)) {
PRINT_ERROR("Invalid RTT %x (TM fn %x)", req_hdr->rtt,
function);
err = -1;
rc = -1;
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
goto reject;
}
@@ -1781,8 +1789,9 @@ static void execute_task_management(struct iscsi_cmnd *req)
switch (function) {
case ISCSI_FUNCTION_ABORT_TASK:
err = cmnd_abort(req);
if (err == 0) {
rc = -1;
status = cmnd_abort(req);
if (status == 0) {
params.fn = SCST_ABORT_TASK;
params.tag = req_hdr->rtt;
params.tag_set = 1;
@@ -1791,8 +1800,9 @@ static void execute_task_management(struct iscsi_cmnd *req)
params.lun_set = 1;
params.cmd_sn = req_hdr->cmd_sn;
params.cmd_sn_set = 1;
err = scst_rx_mgmt_fn(conn->session->scst_sess,
rc = scst_rx_mgmt_fn(conn->session->scst_sess,
&params);
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
}
break;
case ISCSI_FUNCTION_ABORT_TASK_SET:
@@ -1803,8 +1813,9 @@ static void execute_task_management(struct iscsi_cmnd *req)
params.lun_set = 1;
params.cmd_sn = req_hdr->cmd_sn;
params.cmd_sn_set = 1;
err = scst_rx_mgmt_fn(conn->session->scst_sess,
rc = scst_rx_mgmt_fn(conn->session->scst_sess,
&params);
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
break;
case ISCSI_FUNCTION_CLEAR_TASK_SET:
task_set_abort(req);
@@ -1814,8 +1825,9 @@ static void execute_task_management(struct iscsi_cmnd *req)
params.lun_set = 1;
params.cmd_sn = req_hdr->cmd_sn;
params.cmd_sn_set = 1;
err = scst_rx_mgmt_fn(conn->session->scst_sess,
rc = scst_rx_mgmt_fn(conn->session->scst_sess,
&params);
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
break;
case ISCSI_FUNCTION_CLEAR_ACA:
params.fn = SCST_CLEAR_ACA;
@@ -1824,8 +1836,9 @@ static void execute_task_management(struct iscsi_cmnd *req)
params.lun_set = 1;
params.cmd_sn = req_hdr->cmd_sn;
params.cmd_sn_set = 1;
err = scst_rx_mgmt_fn(conn->session->scst_sess,
rc = scst_rx_mgmt_fn(conn->session->scst_sess,
&params);
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
break;
case ISCSI_FUNCTION_TARGET_COLD_RESET:
case ISCSI_FUNCTION_TARGET_WARM_RESET:
@@ -1833,8 +1846,9 @@ static void execute_task_management(struct iscsi_cmnd *req)
params.fn = SCST_TARGET_RESET;
params.cmd_sn = req_hdr->cmd_sn;
params.cmd_sn_set = 1;
err = scst_rx_mgmt_fn(conn->session->scst_sess,
rc = scst_rx_mgmt_fn(conn->session->scst_sess,
&params);
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
break;
case ISCSI_FUNCTION_LOGICAL_UNIT_RESET:
target_abort(req, 0);
@@ -1844,25 +1858,26 @@ static void execute_task_management(struct iscsi_cmnd *req)
params.lun_set = 1;
params.cmd_sn = req_hdr->cmd_sn;
params.cmd_sn_set = 1;
err = scst_rx_mgmt_fn(conn->session->scst_sess,
rc = scst_rx_mgmt_fn(conn->session->scst_sess,
&params);
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
break;
case ISCSI_FUNCTION_TASK_REASSIGN:
iscsi_send_task_mgmt_resp(req,
ISCSI_RESPONSE_FUNCTION_UNSUPPORTED);
rc = -1;
status = ISCSI_RESPONSE_FUNCTION_UNSUPPORTED;
break;
default:
PRINT_ERROR("Unknown TM function %d", function);
iscsi_send_task_mgmt_resp(req,
ISCSI_RESPONSE_FUNCTION_REJECTED);
rc = -1;
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
break;
}
reject:
if (err != 0) {
iscsi_send_task_mgmt_resp(req,
ISCSI_RESPONSE_FUNCTION_REJECTED);
}
if (rc != 0)
iscsi_send_task_mgmt_resp(req, status);
return;
}
static void noop_out_exec(struct iscsi_cmnd *req)
@@ -2140,7 +2155,7 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
while (1) {
session->exp_cmd_sn = ++cmd_sn;
if (unlikely(session->tm_active)) {
if (unlikely(session->tm_active > 0)) {
if (before(cmd_sn, session->tm_sn)) {
struct iscsi_conn *conn = cmnd->conn;
@@ -2476,7 +2491,11 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
u8 *sense = scst_cmd_get_sense_buffer(scst_cmd);
int sense_len = scst_cmd_get_sense_buffer_len(scst_cmd);
int old_state = req->scst_state;
#if 0 /* temp. ToDo */
bool single_only = !scst_get_long_xmit(scst_cmd);
#else
bool single_only = 0;
#endif
scst_cmd_set_tgt_priv(scst_cmd, NULL);
@@ -2622,10 +2641,12 @@ static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess)
TRACE(TRACE_MGMT_MINOR, "Sending delayed rsp %p", tm_rsp);
sess->tm_rsp = NULL;
sess->tm_active = 0;
sess->tm_active--;
spin_unlock(&sess->sn_lock);
sBUG_ON(sess->tm_active < 0);
iscsi_cmnd_init_write(tm_rsp,
ISCSI_INIT_WRITE_REMOVE_HASH | ISCSI_INIT_WRITE_WAKE);
@@ -2676,9 +2697,11 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status)
spin_unlock(&sess->sn_lock);
goto out_release;
}
sess->tm_active = 0;
sess->tm_active--;
spin_unlock(&sess->sn_lock);
sBUG_ON(sess->tm_active < 0);
iscsi_cmnd_init_write(rsp,
ISCSI_INIT_WRITE_REMOVE_HASH | ISCSI_INIT_WRITE_WAKE);

View File

@@ -99,8 +99,7 @@ struct iscsi_session {
u32 exp_cmd_sn; /* protected by sn_lock */
/* All 3 protected by sn_lock */
unsigned int tm_active:1;
unsigned int shutting_down:1; /* Let's save some cache footprint by putting it here */
int tm_active;
u32 tm_sn;
struct iscsi_cmnd *tm_rsp;
@@ -118,6 +117,7 @@ struct iscsi_session {
/* Both don't need any protection */
char *initiator_name;
unsigned int shutting_down:1;
u64 sid;
};

View File

@@ -35,7 +35,7 @@
#ifdef DEBUG
#define ISCSI_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_LINE | TRACE_PID | \
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | TRACE_MGMT_DEBUG | \
TRACE_MINOR | TRACE_SPECIAL | TRACE_CONN_OC | TRACE_CONN_OC_DBG)
TRACE_MINOR | TRACE_SPECIAL | TRACE_CONN_OC)
#else
#define ISCSI_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
TRACE_MINOR | TRACE_SPECIAL)

View File

@@ -61,16 +61,17 @@ static void iscsi_check_closewait(struct iscsi_conn *conn)
TRACE_ENTRY();
if ((conn->sock->sk->sk_state != TCP_CLOSE_WAIT) &&
(conn->sock->sk->sk_state != TCP_CLOSE)) {
TRACE_CONN_CLOSE("sk_state %d, skipping",
conn->sock->sk->sk_state);
TRACE_CONN_CLOSE("conn %p, sk_state %d", conn, conn->sock->sk->sk_state);
if (conn->sock->sk->sk_state != TCP_CLOSE) {
TRACE_CONN_CLOSE_DBG("conn %p, skipping", conn);
goto out;
}
/*
* No data are going to be sent, so all being sent buffers can be freed
* now. Strange that TCP doesn't do that itself.
* No data are going to be sent, so all queued buffers can be freed
* now. In many cases TCP does that only in close(), but we can't rely
* on user space on calling it.
*/
again:
@@ -235,7 +236,8 @@ static void close_conn(struct iscsi_conn *conn)
TRACE(TRACE_MGMT_MINOR, "Dropping delayed TM rsp %p",
tm_rsp);
session->tm_rsp = NULL;
session->tm_active = 0;
session->tm_active--;
WARN_ON(session->tm_active < 0);
spin_unlock(&session->sn_lock);
mutex_unlock(&target->target_mutex);
@@ -329,10 +331,18 @@ static void close_conn(struct iscsi_conn *conn)
iscsi_make_conn_wr_active(conn);
if (time_after(jiffies, start_waiting + 7*HZ)) {
TRACE_CONN_CLOSE("%s", "Wait time expired");
TRACE_CONN_CLOSE("Wait time expired (conn %p, "
"sk_state %d)", conn, conn->sock->sk->sk_state);
conn->sock->ops->shutdown(conn->sock, SEND_SHUTDOWN);
}
if (time_after(jiffies, start_waiting + 15*HZ)) {
TRACE_CONN_CLOSE("Wait time after shutdown expired "
"(conn %p, sk_state %d)", conn,
conn->sock->sk->sk_state);
conn->sock->sk->sk_prot->disconnect(conn->sock->sk, 0);
}
msleep(200);
TRACE_CONN_CLOSE("conn %p, conn_ref_cnt %d left, wr_state %d, "
@@ -914,6 +924,7 @@ static int write_data(struct iscsi_conn *conn)
spin_unlock_bh(&conn->write_list_lock);
}
#if 0 /* temp. ToDo */
if (!timer_pending(&conn->rsp_timer)) {
sBUG_ON(!ref_cmd->on_written_list);
spin_lock_bh(&conn->write_list_lock);
@@ -925,6 +936,7 @@ static int write_data(struct iscsi_conn *conn)
}
spin_unlock_bh(&conn->write_list_lock);
}
#endif
file = conn->file;
saved_size = size = conn->write_size;

View File

@@ -2571,6 +2571,43 @@ out:
return res;
}
static void vdisk_report_registering(const char *type,
const struct scst_vdisk_dev *virt_dev)
{
char buf[128];
int i, j;
i = snprintf(buf, sizeof(buf), "Registering virtual %s device %s",
type, virt_dev->name);
j = i;
if (virt_dev->wt_flag)
i += snprintf(&buf[i], sizeof(buf) - i, " (WRITE_THROUGH");
if (virt_dev->nv_cache)
i += snprintf(&buf[i], sizeof(buf) - i, "%sNV_CACHE",
(j == i) ? "(" : ", ");
if (virt_dev->rd_only_flag)
i += snprintf(&buf[i], sizeof(buf) - i, "%sREAD_ONLY",
(j == i) ? "(" : ", ");
if (virt_dev->o_direct_flag)
i += snprintf(&buf[i], sizeof(buf) - i, "%sO_DIRECT",
(j == i) ? "(" : ", ");
if (virt_dev->nullio)
i += snprintf(&buf[i], sizeof(buf) - i, "%sNULLIO",
(j == i) ? "(" : ", ");
if (j == i)
PRINT_INFO("%s", buf);
else
PRINT_INFO("%s)", buf);
return;
}
/*
* Called when a file in the /proc/VDISK_NAME/VDISK_NAME is written
*/
@@ -2753,14 +2790,17 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
list_add_tail(&virt_dev->vdisk_dev_list_entry,
&vdisk_dev_list);
if (virt_dev->blockio)
if (virt_dev->blockio) {
vdisk_report_registering("BLOCKIO", virt_dev);
virt_dev->virt_id =
scst_register_virtual_device(&vdisk_blk_devtype,
virt_dev->name);
else
} else {
vdisk_report_registering("FILEIO", virt_dev);
virt_dev->virt_id =
scst_register_virtual_device(&vdisk_devtype,
virt_dev->name);
}
if (virt_dev->virt_id < 0) {
res = virt_dev->virt_id;
goto out_free_vpath;
@@ -2880,6 +2920,8 @@ static int vcdrom_open(char *p, char *name)
list_add_tail(&virt_dev->vdisk_dev_list_entry,
&vcdrom_dev_list);
PRINT_INFO("Registering virtual CDROM %s", name);
virt_dev->virt_id =
scst_register_virtual_device(&vcdrom_devtype,
virt_dev->name);

View File

@@ -719,13 +719,15 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun,
out:
if (res == 0) {
if (dev->virt_name != NULL) {
PRINT_INFO("Added device %s to group %s",
dev->virt_name, acg->acg_name);
PRINT_INFO("Added device %s to group %s (LUN %Ld, "
"rd_only %d)", dev->virt_name, acg->acg_name,
lun, read_only);
} else {
PRINT_INFO("Added device %d:%d:%d:%d to group %s",
dev->scsi_dev->host->host_no,
PRINT_INFO("Added device %d:%d:%d:%d to group %s (LUN "
"%Ld, rd_only %d)", dev->scsi_dev->host->host_no,
dev->scsi_dev->channel, dev->scsi_dev->id,
dev->scsi_dev->lun, acg->acg_name);
dev->scsi_dev->lun, acg->acg_name, lun,
read_only);
}
}
@@ -1568,9 +1570,9 @@ int scst_alloc_space(struct scst_cmd *cmd)
flags |= SCST_POOL_ALLOC_NO_CACHED;
if (unlikely(cmd->bufflen == 0)) {
TRACE(TRACE_MGMT_MINOR, "Data direction %d or/and zero buffer "
"length. Opcode 0x%x, handler %s, target %s",
cmd->data_direction, cmd->cdb[0],
TRACE(TRACE_MGMT_MINOR, "Warning: data direction %d or/and "
"zero buffer length. Opcode 0x%x, handler %s, target "
"%s", cmd->data_direction, cmd->cdb[0],
cmd->dev->handler->name, cmd->tgtt->name);
/*
* Be on the safe side and alloc stub buffer. Neither target

View File

@@ -240,7 +240,9 @@ static inline void scst_make_deferred_commands_active(
spin_lock_irq(&c->cmd_lists->cmd_list_lock);
list_add_tail(&c->cmd_list_entry,
&c->cmd_lists->active_cmd_list);
#if 0 /* temp. ToDo */
if (!curr_cmd->context_processable || curr_cmd->long_xmit)
#endif
wake_up(&c->cmd_lists->cmd_list_waitQ);
spin_unlock_irq(&c->cmd_lists->cmd_list_lock);
}

View File

@@ -476,6 +476,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
PRINT_ERROR("Dev handler supplied data buffer (size %d), "
"is less, than required (size %d)", cmd->bufflen,
orig_bufflen);
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
goto out_error;
}
@@ -487,6 +488,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
PRINT_ERROR("Unknown data transfer length for opcode 0x%x "
"(handler %s, target %s)", cmd->cdb[0],
dev->handler->name, cmd->tgtt->name);
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
goto out_error;
}
@@ -499,6 +501,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
"or sg %p (opcode 0x%x)", dev->handler->name,
cmd->data_direction, cmd->bufflen, state, cmd->sg,
cmd->cdb[0]);
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
goto out_error;
}
#endif
@@ -513,20 +516,27 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
"bufflen %d, expected_transfer_len %d",
cmd->data_direction, cmd->expected_data_direction,
cmd->bufflen, cmd->expected_transfer_len);
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
}
# endif
cmd->data_direction = cmd->expected_data_direction;
cmd->bufflen = cmd->expected_transfer_len;
#else
if (unlikely(cmd->data_direction != cmd->expected_data_direction)) {
PRINT_ERROR("Expected data direction %d for opcode "
"0x%02x (handler %s, target %s) doesn't match "
"decoded value %d", cmd->data_direction,
cmd->cdb[0], dev->handler->name,
cmd->tgtt->name, cmd->expected_data_direction);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_message));
goto out_dev_done;
if (((cmd->expected_data_direction != SCST_DATA_NONE) ||
(cmd->bufflen != 0)) &&
/* Crazy VMware people sometimes do TUR with READ direction */
!(cmd->cdb[0] == TEST_UNIT_READY)) {
PRINT_ERROR("Expected data direction %d for opcode "
"0x%02x (handler %s, target %s) doesn't match "
"decoded value %d", cmd->expected_data_direction,
cmd->cdb[0], dev->handler->name,
cmd->tgtt->name, cmd->data_direction);
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_message));
goto out_dev_done;
}
}
if (unlikely(cmd->bufflen != cmd->expected_transfer_len)) {
TRACE(TRACE_MINOR, "Warning: expected transfer length "
@@ -547,6 +557,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
PRINT_ERROR("Unknown data direction. Opcode 0x%x, handler %s, "
"target %s", cmd->cdb[0], dev->handler->name,
cmd->tgtt->name);
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
goto out_error;
}
@@ -1418,7 +1429,8 @@ static int scst_reserve_local(struct scst_cmd *cmd)
dev = cmd->dev;
scst_block_dev_cmd(cmd, 1);
if (dev->tst == SCST_CONTR_MODE_ONE_TASK_SET)
scst_block_dev_cmd(cmd, 1);
rc = scst_check_local_events(cmd);
if (unlikely(rc != 0))
@@ -1473,7 +1485,8 @@ static int scst_release_local(struct scst_cmd *cmd)
dev = cmd->dev;
scst_block_dev_cmd(cmd, 1);
if (dev->tst == SCST_CONTR_MODE_ONE_TASK_SET)
scst_block_dev_cmd(cmd, 1);
rc = scst_check_local_events(cmd);
if (unlikely(rc != 0))
@@ -3497,7 +3510,7 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
TRACE_ENTRY();
TRACE(((mcmd != NULL) && (mcmd->fn == SCST_ABORT_TASK)) ? TRACE_MGMT_MINOR : TRACE_MGMT,
"Aborting cmd %p (tag %llu)", cmd, cmd->tag);
"Aborting cmd %p (tag %llu, op %x)", cmd, cmd->tag, cmd->cdb[0]);
if (other_ini) {
set_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
@@ -3890,11 +3903,17 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
}
case SCST_TARGET_RESET:
case SCST_ABORT_ALL_TASKS:
case SCST_NEXUS_LOSS_SESS:
case SCST_ABORT_ALL_TASKS_SESS:
case SCST_NEXUS_LOSS:
case SCST_ABORT_ALL_TASKS:
case SCST_UNREG_SESS_TM:
break;
default:
case SCST_ABORT_TASK_SET:
case SCST_CLEAR_ACA:
case SCST_CLEAR_TASK_SET:
case SCST_LUN_RESET:
rc = scst_mgmt_translate_lun(mcmd);
if (rc < 0) {
PRINT_ERROR("Corresponding device for lun %Ld not "
@@ -3904,6 +3923,9 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
} else if (rc != 0)
res = rc;
break;
default:
sBUG();
}
out:
@@ -4315,9 +4337,13 @@ static int scst_mgmt_cmd_check_nexus_loss(struct scst_mgmt_cmd *mcmd)
if ((mcmd->fn == SCST_UNREG_SESS_TM) &&
(mcmd->sess->unreg_cmds_done_fn != NULL)) {
struct scst_session *sess = mcmd->sess;
TRACE_MGMT_DBG("Calling unreg_cmds_done_fn(%p)", sess);
sess->unreg_cmds_done_fn(sess);
TRACE_MGMT_DBG("task_mgmt_all_cmds_done(%p) returned", sess);
/* To prevent scst_mgmt_cmd_send_done() to call it again */
sess->unreg_cmds_done_fn = NULL;
}
mcmd->nexus_loss_check_done = 1;
@@ -4332,6 +4358,7 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
{
struct scst_device *dev;
struct scst_tgt_dev *tgt_dev;
struct scst_session *sess = mcmd->sess;
TRACE_ENTRY();
@@ -4342,13 +4369,20 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
TRACE(TRACE_MGMT_MINOR, "TM command fn %d finished, status %x",
mcmd->fn, mcmd->status);
if (mcmd->sess->tgt->tgtt->task_mgmt_fn_done &&
(mcmd->fn != SCST_UNREG_SESS_TM)) {
TRACE_DBG("Calling target %s task_mgmt_fn_done()",
mcmd->sess->tgt->tgtt->name);
mcmd->sess->tgt->tgtt->task_mgmt_fn_done(mcmd);
TRACE_MGMT_DBG("Target's %s task_mgmt_fn_done() returned",
mcmd->sess->tgt->tgtt->name);
if (mcmd->fn == SCST_UNREG_SESS_TM) {
if (sess->unreg_cmds_done_fn != NULL) {
TRACE_MGMT_DBG("Calling unreg_cmds_done_fn(%p)", sess);
sess->unreg_cmds_done_fn(sess);
TRACE_MGMT_DBG("task_mgmt_all_cmds_done(%p) returned", sess);
}
} else {
if (sess->tgt->tgtt->task_mgmt_fn_done) {
TRACE_DBG("Calling target %s task_mgmt_fn_done(%p)",
sess->tgt->tgtt->name, sess);
sess->tgt->tgtt->task_mgmt_fn_done(mcmd);
TRACE_MGMT_DBG("Target's %s task_mgmt_fn_done() "
"returned", sess->tgt->tgtt->name);
}
}
if (mcmd->needs_unblocking) {