Avoid that the iSCSI target driver complains about "Initial page entry out-of-bounds" and closes the connection if the SCSI Data-Out buffer is larger than the buffer size specified through the CDB. This patch prevents that running the libiscsi regression tests against LIO trigger an infinite loop of libiscsi submitting a command, LIO closing the connection and libiscsi resubmitting the same command. Signed-off-by: Bart Van Assche <bart.vanassche@xxxxxxxxxxx> Cc: Hannes Reinecke <hare@xxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: Andy Grover <agrover@xxxxxxxxxx> Cc: David Disseldorp <ddiss@xxxxxxx> Cc: <stable@xxxxxxxxxxxxxxx> --- drivers/target/target_core_transport.c | 29 ++++++++++------------------- include/target/target_core_base.h | 4 +++- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index df1ceb2dd110..86b6b0238975 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1159,11 +1159,11 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) if (cmd->unknown_data_length) { cmd->data_length = size; - } else if (size != cmd->data_length) { + } else if (size != cmd->buffer_length) { pr_warn("TARGET_CORE[%s]: Expected Transfer Length:" " %u does not match SCSI CDB Length: %u for SAM Opcode:" " 0x%02x\n", cmd->se_tfo->get_fabric_name(), - cmd->data_length, size, cmd->t_task_cdb[0]); + cmd->buffer_length, size, cmd->t_task_cdb[0]); if (cmd->data_direction == DMA_TO_DEVICE && cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { @@ -1183,7 +1183,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) } /* * For the overflow case keep the existing fabric provided - * ->data_length. Otherwise for the underflow case, reset + * ->buffer_length. Otherwise for the underflow case, reset * ->data_length to the smaller SCSI expected data transfer * length. */ @@ -1227,6 +1227,7 @@ void transport_init_se_cmd( cmd->se_tfo = tfo; cmd->se_sess = se_sess; + cmd->buffer_length = data_length; cmd->data_length = data_length; cmd->data_direction = data_direction; cmd->sam_task_attr = task_attr; @@ -2412,41 +2413,31 @@ transport_generic_new_cmd(struct se_cmd *cmd) * beforehand. */ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) && - cmd->data_length) { + cmd->buffer_length) { if ((cmd->se_cmd_flags & SCF_BIDI) || (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) { - u32 bidi_length; - - if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) - bidi_length = cmd->t_task_nolb * - cmd->se_dev->dev_attrib.block_size; - else - bidi_length = cmd->data_length; - ret = target_alloc_sgl(&cmd->t_bidi_data_sg, &cmd->t_bidi_data_nents, - bidi_length, zero_flag, false); + cmd->buffer_length, zero_flag, + false); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents, - cmd->data_length, zero_flag, false); + cmd->buffer_length, zero_flag, false); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } else if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && - cmd->data_length) { + cmd->buffer_length) { /* * Special case for COMPARE_AND_WRITE with fabrics * using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC. */ - u32 caw_length = cmd->t_task_nolb * - cmd->se_dev->dev_attrib.block_size; - ret = target_alloc_sgl(&cmd->t_bidi_data_sg, &cmd->t_bidi_data_nents, - caw_length, zero_flag, false); + cmd->buffer_length, zero_flag, false); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 49cd03c2d943..0660585cb03d 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -455,7 +455,9 @@ struct se_cmd { enum transport_state_table t_state; /* See se_cmd_flags_table */ u32 se_cmd_flags; - /* Total size in bytes associated with command */ + /* Length of Data-Out or Data-In buffer */ + u32 buffer_length; + /* Number of bytes affected on storage medium */ u32 data_length; u32 residual_count; u64 orig_fe_lun; -- 2.12.2