Skip to content

Commit

Permalink
target: Report correct response length for some commands
Browse files Browse the repository at this point in the history
When an initiator sends an allocation length bigger than what its
command consumes, the target should only return the actual response data
and set the residual length to the unused part of the allocation length.

Add a helper function that command handlers (INQUIRY, READ CAPACITY,
etc) can use to do this correctly, and use this code to get the correct
residual for commands that don't use the full initiator allocation in the
handlers for READ CAPACITY, READ CAPACITY(16), INQUIRY, MODE SENSE and
REPORT LUNS.

This addresses a handful of failures as reported by Christophe with
the Windows Certification Kit:

  http://permalink.gmane.org/gmane.linux.scsi.target.devel/6515

Signed-off-by: Roland Dreier <roland@purestorage.com>
Tested-by: Christophe Vu-Brugier <cvubrugier@yahoo.fr>
Cc: stable@vger.kernel.org # 3.10+
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
  • Loading branch information
Roland Dreier authored and Nicholas Bellinger committed Jun 11, 2014
1 parent c52716d commit 2426bd4
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 5 deletions.
4 changes: 2 additions & 2 deletions drivers/target/target_core_sbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd)
transport_kunmap_data_sg(cmd);
}

target_complete_cmd(cmd, GOOD);
target_complete_cmd_with_length(cmd, GOOD, 8);
return 0;
}

Expand Down Expand Up @@ -137,7 +137,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
transport_kunmap_data_sg(cmd);
}

target_complete_cmd(cmd, GOOD);
target_complete_cmd_with_length(cmd, GOOD, 32);
return 0;
}

Expand Down
9 changes: 6 additions & 3 deletions drivers/target/target_core_spc.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
unsigned char *buf;
sense_reason_t ret;
int p;
int len = 0;

buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
if (!buf) {
Expand All @@ -737,13 +738,15 @@ spc_emulate_inquiry(struct se_cmd *cmd)
}

ret = spc_emulate_inquiry_std(cmd, buf);
len = buf[4] + 5;
goto out;
}

for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) {
if (cdb[2] == evpd_handlers[p].page) {
buf[1] = cdb[2];
ret = evpd_handlers[p].emulate(cmd, buf);
len = get_unaligned_be16(&buf[2]) + 4;
goto out;
}
}
Expand All @@ -760,7 +763,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
kfree(buf);

if (!ret)
target_complete_cmd(cmd, GOOD);
target_complete_cmd_with_length(cmd, GOOD, len);
return ret;
}

Expand Down Expand Up @@ -1098,7 +1101,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
transport_kunmap_data_sg(cmd);
}

target_complete_cmd(cmd, GOOD);
target_complete_cmd_with_length(cmd, GOOD, length);
return 0;
}

Expand Down Expand Up @@ -1274,7 +1277,7 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
buf[3] = (lun_count & 0xff);
transport_kunmap_data_sg(cmd);

target_complete_cmd(cmd, GOOD);
target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
return 0;
}
EXPORT_SYMBOL(spc_emulate_report_luns);
Expand Down
17 changes: 17 additions & 0 deletions drivers/target/target_core_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,23 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
}
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 (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
cmd->residual_count += cmd->data_length - length;
} else {
cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
cmd->residual_count = cmd->data_length - length;
}

cmd->data_length = length;
}

target_complete_cmd(cmd, scsi_status);
}
EXPORT_SYMBOL(target_complete_cmd_with_length);

static void target_add_to_state_list(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
Expand Down
1 change: 1 addition & 0 deletions include/target/target_core_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ int transport_subsystem_register(struct se_subsystem_api *);
void transport_subsystem_release(struct se_subsystem_api *);

void target_complete_cmd(struct se_cmd *, u8);
void target_complete_cmd_with_length(struct se_cmd *, u8, int);

sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd);
Expand Down

0 comments on commit 2426bd4

Please sign in to comment.