aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorRoland Dreier <roland@purestorage.com>2014-06-10 14:07:47 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2014-06-11 15:15:30 -0400
commit2426bd456a61407388b6e61fc5f98dbcbebc50e2 (patch)
tree4d074c38acefad0aca18b9da752bec2abb6476a7 /drivers/target
parentc52716defd6ec7e89c510c740de7ec3478008f28 (diff)
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>
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/target_core_sbc.c4
-rw-r--r--drivers/target/target_core_spc.c9
-rw-r--r--drivers/target/target_core_transport.c17
3 files changed, 25 insertions, 5 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 97a33603795d..1d3a626bf24f 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -81,7 +81,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd)
81 transport_kunmap_data_sg(cmd); 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 return 0; 85 return 0;
86} 86}
87 87
@@ -137,7 +137,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
137 transport_kunmap_data_sg(cmd); 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 return 0; 141 return 0;
142} 142}
143 143
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 17b5b7e099fa..6cd7222738fc 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -716,6 +716,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
716 unsigned char *buf; 716 unsigned char *buf;
717 sense_reason_t ret; 717 sense_reason_t ret;
718 int p; 718 int p;
719 int len = 0;
719 720
720 buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); 721 buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
721 if (!buf) { 722 if (!buf) {
@@ -737,6 +738,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
737 } 738 }
738 739
739 ret = spc_emulate_inquiry_std(cmd, buf); 740 ret = spc_emulate_inquiry_std(cmd, buf);
741 len = buf[4] + 5;
740 goto out; 742 goto out;
741 } 743 }
742 744
@@ -744,6 +746,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
744 if (cdb[2] == evpd_handlers[p].page) { 746 if (cdb[2] == evpd_handlers[p].page) {
745 buf[1] = cdb[2]; 747 buf[1] = cdb[2];
746 ret = evpd_handlers[p].emulate(cmd, buf); 748 ret = evpd_handlers[p].emulate(cmd, buf);
749 len = get_unaligned_be16(&buf[2]) + 4;
747 goto out; 750 goto out;
748 } 751 }
749 } 752 }
@@ -760,7 +763,7 @@ out:
760 kfree(buf); 763 kfree(buf);
761 764
762 if (!ret) 765 if (!ret)
763 target_complete_cmd(cmd, GOOD); 766 target_complete_cmd_with_length(cmd, GOOD, len);
764 return ret; 767 return ret;
765} 768}
766 769
@@ -1098,7 +1101,7 @@ set_length:
1098 transport_kunmap_data_sg(cmd); 1101 transport_kunmap_data_sg(cmd);
1099 } 1102 }
1100 1103
1101 target_complete_cmd(cmd, GOOD); 1104 target_complete_cmd_with_length(cmd, GOOD, length);
1102 return 0; 1105 return 0;
1103} 1106}
1104 1107
@@ -1274,7 +1277,7 @@ done:
1274 buf[3] = (lun_count & 0xff); 1277 buf[3] = (lun_count & 0xff);
1275 transport_kunmap_data_sg(cmd); 1278 transport_kunmap_data_sg(cmd);
1276 1279
1277 target_complete_cmd(cmd, GOOD); 1280 target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
1278 return 0; 1281 return 0;
1279} 1282}
1280EXPORT_SYMBOL(spc_emulate_report_luns); 1283EXPORT_SYMBOL(spc_emulate_report_luns);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 15dbf6e97289..c9e8b35a954f 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -703,6 +703,23 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
703} 703}
704EXPORT_SYMBOL(target_complete_cmd); 704EXPORT_SYMBOL(target_complete_cmd);
705 705
706void 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}
721EXPORT_SYMBOL(target_complete_cmd_with_length);
722
706static void target_add_to_state_list(struct se_cmd *cmd) 723static void target_add_to_state_list(struct se_cmd *cmd)
707{ 724{
708 struct se_device *dev = cmd->se_dev; 725 struct se_device *dev = cmd->se_dev;