Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger: "The most notable item is IBM virtual SCSI target driver, that was originally ported to target-core back in 2010 by Tomo-san, and has been brought forward to v4.x code by Bryant Ly, Michael Cyr and co over the last months. Also included are two ORDERED task related bug-fixes Bryant + Michael found along the way using ibmvscsis with AIX guests, plus a few miscellaneous target-core + iscsi-target bug-fixes with associated stable tags" * 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: target: fix spelling mistake: "limitiation" -> "limitation" target: Fix residual overflow handling in target_complete_cmd_with_length tcm_fc: set and unset FCP_SPPF_TARG_FCN iscsi-target: Fix panic when adding second TCP connection to iSCSI session ibmvscsis: Initial commit of IBM VSCSI Tgt Driver target: Fix ordered task CHECK_CONDITION early exception handling target: Fix ordered task target_setup_cmd_from_cdb exception hang target: Fix max_unmap_lba_count calc overflow target: Fix race between iscsi-target connection shutdown + ABORT_TASK target: Fix missing complete during ABORT_TASK + CMD_T_FABRIC_STOP
This commit is contained in:
@@ -492,7 +492,8 @@ void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
|
||||
bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD);
|
||||
|
||||
spin_lock_bh(&conn->cmd_lock);
|
||||
if (!list_empty(&cmd->i_conn_node))
|
||||
if (!list_empty(&cmd->i_conn_node) &&
|
||||
!(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP))
|
||||
list_del_init(&cmd->i_conn_node);
|
||||
spin_unlock_bh(&conn->cmd_lock);
|
||||
|
||||
@@ -4034,6 +4035,7 @@ int iscsi_target_rx_thread(void *arg)
|
||||
|
||||
static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
|
||||
{
|
||||
LIST_HEAD(tmp_list);
|
||||
struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
|
||||
struct iscsi_session *sess = conn->sess;
|
||||
/*
|
||||
@@ -4042,18 +4044,26 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
|
||||
* has been reset -> returned sleeping pre-handler state.
|
||||
*/
|
||||
spin_lock_bh(&conn->cmd_lock);
|
||||
list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
|
||||
list_splice_init(&conn->conn_cmd_list, &tmp_list);
|
||||
|
||||
list_del_init(&cmd->i_conn_node);
|
||||
spin_unlock_bh(&conn->cmd_lock);
|
||||
list_for_each_entry(cmd, &tmp_list, i_conn_node) {
|
||||
struct se_cmd *se_cmd = &cmd->se_cmd;
|
||||
|
||||
iscsit_increment_maxcmdsn(cmd, sess);
|
||||
|
||||
iscsit_free_cmd(cmd, true);
|
||||
|
||||
spin_lock_bh(&conn->cmd_lock);
|
||||
if (se_cmd->se_tfo != NULL) {
|
||||
spin_lock(&se_cmd->t_state_lock);
|
||||
se_cmd->transport_state |= CMD_T_FABRIC_STOP;
|
||||
spin_unlock(&se_cmd->t_state_lock);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&conn->cmd_lock);
|
||||
|
||||
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
|
||||
list_del_init(&cmd->i_conn_node);
|
||||
|
||||
iscsit_increment_maxcmdsn(cmd, sess);
|
||||
iscsit_free_cmd(cmd, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void iscsit_stop_timers_for_cmds(
|
||||
|
@@ -1371,8 +1371,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
|
||||
}
|
||||
login->zero_tsih = zero_tsih;
|
||||
|
||||
conn->sess->se_sess->sup_prot_ops =
|
||||
conn->conn_transport->iscsit_get_sup_prot_ops(conn);
|
||||
if (conn->sess)
|
||||
conn->sess->se_sess->sup_prot_ops =
|
||||
conn->conn_transport->iscsit_get_sup_prot_ops(conn);
|
||||
|
||||
tpg = conn->tpg;
|
||||
if (!tpg) {
|
||||
|
@@ -821,13 +821,15 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
|
||||
* in ATA and we need to set TPE=1
|
||||
*/
|
||||
bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
|
||||
struct request_queue *q, int block_size)
|
||||
struct request_queue *q)
|
||||
{
|
||||
int block_size = queue_logical_block_size(q);
|
||||
|
||||
if (!blk_queue_discard(q))
|
||||
return false;
|
||||
|
||||
attrib->max_unmap_lba_count = (q->limits.max_discard_sectors << 9) /
|
||||
block_size;
|
||||
attrib->max_unmap_lba_count =
|
||||
q->limits.max_discard_sectors >> (ilog2(block_size) - 9);
|
||||
/*
|
||||
* Currently hardcoded to 1 in Linux/SCSI code..
|
||||
*/
|
||||
|
@@ -161,8 +161,7 @@ static int fd_configure_device(struct se_device *dev)
|
||||
dev_size, div_u64(dev_size, fd_dev->fd_block_size),
|
||||
fd_dev->fd_block_size);
|
||||
|
||||
if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
|
||||
fd_dev->fd_block_size))
|
||||
if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
|
||||
pr_debug("IFILE: BLOCK Discard support available,"
|
||||
" disabled by default\n");
|
||||
/*
|
||||
@@ -523,7 +522,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
|
||||
*/
|
||||
if (cmd->data_length > FD_MAX_BYTES) {
|
||||
pr_err("FILEIO: Not able to process I/O of %u bytes due to"
|
||||
"FD_MAX_BYTES: %u iovec count limitiation\n",
|
||||
"FD_MAX_BYTES: %u iovec count limitation\n",
|
||||
cmd->data_length, FD_MAX_BYTES);
|
||||
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
}
|
||||
|
@@ -121,8 +121,7 @@ static int iblock_configure_device(struct se_device *dev)
|
||||
dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q);
|
||||
dev->dev_attrib.hw_queue_depth = q->nr_requests;
|
||||
|
||||
if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
|
||||
dev->dev_attrib.hw_block_size))
|
||||
if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
|
||||
pr_debug("IBLOCK: BLOCK Discard support available,"
|
||||
" disabled by default\n");
|
||||
|
||||
|
@@ -146,6 +146,7 @@ sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
|
||||
void target_qf_do_work(struct work_struct *work);
|
||||
bool target_check_wce(struct se_device *dev);
|
||||
bool target_check_fua(struct se_device *dev);
|
||||
void __target_execute_cmd(struct se_cmd *, bool);
|
||||
|
||||
/* target_core_stat.c */
|
||||
void target_stat_setup_dev_default_groups(struct se_device *);
|
||||
|
@@ -602,7 +602,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
|
||||
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
|
||||
spin_unlock_irq(&cmd->t_state_lock);
|
||||
|
||||
__target_execute_cmd(cmd);
|
||||
__target_execute_cmd(cmd, false);
|
||||
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
@@ -754,7 +754,15 @@ EXPORT_SYMBOL(target_complete_cmd);
|
||||
|
||||
void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
|
||||
{
|
||||
if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
|
||||
if (scsi_status != SAM_STAT_GOOD) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate new residual count based upon length of SCSI data
|
||||
* transferred.
|
||||
*/
|
||||
if (length < cmd->data_length) {
|
||||
if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
|
||||
cmd->residual_count += cmd->data_length - length;
|
||||
} else {
|
||||
@@ -763,6 +771,12 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len
|
||||
}
|
||||
|
||||
cmd->data_length = length;
|
||||
} else if (length > cmd->data_length) {
|
||||
cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
|
||||
cmd->residual_count = length - cmd->data_length;
|
||||
} else {
|
||||
cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT);
|
||||
cmd->residual_count = 0;
|
||||
}
|
||||
|
||||
target_complete_cmd(cmd, scsi_status);
|
||||
@@ -1303,23 +1317,6 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
|
||||
|
||||
trace_target_sequencer_start(cmd);
|
||||
|
||||
/*
|
||||
* Check for an existing UNIT ATTENTION condition
|
||||
*/
|
||||
ret = target_scsi3_ua_check(cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = target_alua_state_check(cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = target_check_reservation(cmd);
|
||||
if (ret) {
|
||||
cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dev->transport->parse_cdb(cmd);
|
||||
if (ret == TCM_UNSUPPORTED_SCSI_OPCODE)
|
||||
pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n",
|
||||
@@ -1761,20 +1758,45 @@ queue_full:
|
||||
}
|
||||
EXPORT_SYMBOL(transport_generic_request_failure);
|
||||
|
||||
void __target_execute_cmd(struct se_cmd *cmd)
|
||||
void __target_execute_cmd(struct se_cmd *cmd, bool do_checks)
|
||||
{
|
||||
sense_reason_t ret;
|
||||
|
||||
if (cmd->execute_cmd) {
|
||||
ret = cmd->execute_cmd(cmd);
|
||||
if (ret) {
|
||||
spin_lock_irq(&cmd->t_state_lock);
|
||||
cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
|
||||
spin_unlock_irq(&cmd->t_state_lock);
|
||||
if (!cmd->execute_cmd) {
|
||||
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
||||
goto err;
|
||||
}
|
||||
if (do_checks) {
|
||||
/*
|
||||
* Check for an existing UNIT ATTENTION condition after
|
||||
* target_handle_task_attr() has done SAM task attr
|
||||
* checking, and possibly have already defered execution
|
||||
* out to target_restart_delayed_cmds() context.
|
||||
*/
|
||||
ret = target_scsi3_ua_check(cmd);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
transport_generic_request_failure(cmd, ret);
|
||||
ret = target_alua_state_check(cmd);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = target_check_reservation(cmd);
|
||||
if (ret) {
|
||||
cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = cmd->execute_cmd(cmd);
|
||||
if (!ret)
|
||||
return;
|
||||
err:
|
||||
spin_lock_irq(&cmd->t_state_lock);
|
||||
cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
|
||||
spin_unlock_irq(&cmd->t_state_lock);
|
||||
|
||||
transport_generic_request_failure(cmd, ret);
|
||||
}
|
||||
|
||||
static int target_write_prot_action(struct se_cmd *cmd)
|
||||
@@ -1819,6 +1841,8 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
|
||||
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
|
||||
return false;
|
||||
|
||||
cmd->se_cmd_flags |= SCF_TASK_ATTR_SET;
|
||||
|
||||
/*
|
||||
* Check for the existence of HEAD_OF_QUEUE, and if true return 1
|
||||
* to allow the passed struct se_cmd list of tasks to the front of the list.
|
||||
@@ -1899,7 +1923,7 @@ void target_execute_cmd(struct se_cmd *cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
__target_execute_cmd(cmd);
|
||||
__target_execute_cmd(cmd, true);
|
||||
}
|
||||
EXPORT_SYMBOL(target_execute_cmd);
|
||||
|
||||
@@ -1923,7 +1947,7 @@ static void target_restart_delayed_cmds(struct se_device *dev)
|
||||
list_del(&cmd->se_delayed_node);
|
||||
spin_unlock(&dev->delayed_cmd_lock);
|
||||
|
||||
__target_execute_cmd(cmd);
|
||||
__target_execute_cmd(cmd, true);
|
||||
|
||||
if (cmd->sam_task_attr == TCM_ORDERED_TAG)
|
||||
break;
|
||||
@@ -1941,6 +1965,9 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
|
||||
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
|
||||
return;
|
||||
|
||||
if (!(cmd->se_cmd_flags & SCF_TASK_ATTR_SET))
|
||||
goto restart;
|
||||
|
||||
if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
|
||||
atomic_dec_mb(&dev->simple_cmds);
|
||||
dev->dev_cur_ordered_id++;
|
||||
@@ -1957,7 +1984,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
|
||||
pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n",
|
||||
dev->dev_cur_ordered_id);
|
||||
}
|
||||
|
||||
restart:
|
||||
target_restart_delayed_cmds(dev);
|
||||
}
|
||||
|
||||
@@ -2557,15 +2584,10 @@ static void target_release_cmd_kref(struct kref *kref)
|
||||
bool fabric_stop;
|
||||
|
||||
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
|
||||
if (list_empty(&se_cmd->se_cmd_list)) {
|
||||
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
|
||||
target_free_cmd_mem(se_cmd);
|
||||
se_cmd->se_tfo->release_cmd(se_cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock(&se_cmd->t_state_lock);
|
||||
fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP);
|
||||
fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) &&
|
||||
(se_cmd->transport_state & CMD_T_ABORTED);
|
||||
spin_unlock(&se_cmd->t_state_lock);
|
||||
|
||||
if (se_cmd->cmd_wait_set || fabric_stop) {
|
||||
|
@@ -91,6 +91,7 @@ static void ft_tport_delete(struct ft_tport *tport)
|
||||
|
||||
ft_sess_delete_all(tport);
|
||||
lport = tport->lport;
|
||||
lport->service_params &= ~FCP_SPPF_TARG_FCN;
|
||||
BUG_ON(tport != lport->prov[FC_TYPE_FCP]);
|
||||
RCU_INIT_POINTER(lport->prov[FC_TYPE_FCP], NULL);
|
||||
|
||||
@@ -110,6 +111,7 @@ void ft_lport_add(struct fc_lport *lport, void *arg)
|
||||
{
|
||||
mutex_lock(&ft_lport_lock);
|
||||
ft_tport_get(lport);
|
||||
lport->service_params |= FCP_SPPF_TARG_FCN;
|
||||
mutex_unlock(&ft_lport_lock);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user