Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

target: Report correct response length for some commands

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>

authored by

Roland Dreier and committed by
Nicholas Bellinger
2426bd45 c52716de

+26 -5
+2 -2
drivers/target/target_core_sbc.c
··· 81 81 transport_kunmap_data_sg(cmd); 82 82 } 83 83 84 - target_complete_cmd(cmd, GOOD); 84 + target_complete_cmd_with_length(cmd, GOOD, 8); 85 85 return 0; 86 86 } 87 87 ··· 137 137 transport_kunmap_data_sg(cmd); 138 138 } 139 139 140 - target_complete_cmd(cmd, GOOD); 140 + target_complete_cmd_with_length(cmd, GOOD, 32); 141 141 return 0; 142 142 } 143 143
+6 -3
drivers/target/target_core_spc.c
··· 716 716 unsigned char *buf; 717 717 sense_reason_t ret; 718 718 int p; 719 + int len = 0; 719 720 720 721 buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); 721 722 if (!buf) { ··· 738 737 } 739 738 740 739 ret = spc_emulate_inquiry_std(cmd, buf); 740 + len = buf[4] + 5; 741 741 goto out; 742 742 } 743 743 ··· 746 744 if (cdb[2] == evpd_handlers[p].page) { 747 745 buf[1] = cdb[2]; 748 746 ret = evpd_handlers[p].emulate(cmd, buf); 747 + len = get_unaligned_be16(&buf[2]) + 4; 749 748 goto out; 750 749 } 751 750 } ··· 763 760 kfree(buf); 764 761 765 762 if (!ret) 766 - target_complete_cmd(cmd, GOOD); 763 + target_complete_cmd_with_length(cmd, GOOD, len); 767 764 return ret; 768 765 } 769 766 ··· 1101 1098 transport_kunmap_data_sg(cmd); 1102 1099 } 1103 1100 1104 - target_complete_cmd(cmd, GOOD); 1101 + target_complete_cmd_with_length(cmd, GOOD, length); 1105 1102 return 0; 1106 1103 } 1107 1104 ··· 1277 1274 buf[3] = (lun_count & 0xff); 1278 1275 transport_kunmap_data_sg(cmd); 1279 1276 1280 - target_complete_cmd(cmd, GOOD); 1277 + target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8); 1281 1278 return 0; 1282 1279 } 1283 1280 EXPORT_SYMBOL(spc_emulate_report_luns);
+17
drivers/target/target_core_transport.c
··· 703 703 } 704 704 EXPORT_SYMBOL(target_complete_cmd); 705 705 706 + void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) 707 + { 708 + if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { 709 + if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { 710 + cmd->residual_count += cmd->data_length - length; 711 + } else { 712 + cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; 713 + cmd->residual_count = cmd->data_length - length; 714 + } 715 + 716 + cmd->data_length = length; 717 + } 718 + 719 + target_complete_cmd(cmd, scsi_status); 720 + } 721 + EXPORT_SYMBOL(target_complete_cmd_with_length); 722 + 706 723 static void target_add_to_state_list(struct se_cmd *cmd) 707 724 { 708 725 struct se_device *dev = cmd->se_dev;
+1
include/target/target_core_backend.h
··· 59 59 void transport_subsystem_release(struct se_subsystem_api *); 60 60 61 61 void target_complete_cmd(struct se_cmd *, u8); 62 + void target_complete_cmd_with_length(struct se_cmd *, u8, int); 62 63 63 64 sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); 64 65 sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd);