aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <roland@purestorage.com>2013-02-08 18:18:39 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2013-02-13 15:16:05 -0500
commitbb992e72f9b751fceb04afeb7736b6a3e50effcf (patch)
tree432d59d06184a8909b4e43e0ae9fdb0dd4bdf1ed
parent33633676df0d16d0685f2fbc571143801bc16e3b (diff)
target: Fix error checking for UNMAP commands
SBC-3 (revision 35) says: The PARAMETER LIST LENGTH field specifies the length in bytes of the UNMAP parameter list that is available to be transferred from the Data-Out Buffer. If the parameter list length is greater than zero and less than 0008h (i.e., eight), then the device server shall terminate the command with CHECK CONDITION status with the sense key set to ILLEGAL REQUEST and the additional sense code set to PARAMETER LIST LENGTH ERROR. A PARAMETER LIST LENGTH set to zero specifies that no data shall be sent. so our sense code for too-short descriptors was wrong, and we were incorrectly failing commands that didn't transfer any descriptors. While we're at it, also handle the UNMAP check: If the ANCHOR bit is set to one, and the ANC_SUP bit in the Logical Block Provisioning VPD page (see 6.6.4) is set to zero, then the device server shall terminate the command with CHECK CONDITION status with the sense key set to ILLEGAL REQUEST and the additional sense code set to INVALID FIELD IN CDB. (chris boot: Fix wrong cut+paste comment in transport_send_check_condition_and_sense) Signed-off-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_iblock.c11
-rw-r--r--drivers/target/target_core_transport.c10
-rw-r--r--include/target/target_core_base.h1
3 files changed, 21 insertions, 1 deletions
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 2f74e17ad3e6..facee5f74fa4 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -391,10 +391,19 @@ iblock_execute_unmap(struct se_cmd *cmd)
391 sense_reason_t ret = 0; 391 sense_reason_t ret = 0;
392 int dl, bd_dl, err; 392 int dl, bd_dl, err;
393 393
394 /* We never set ANC_SUP */
395 if (cmd->t_task_cdb[1])
396 return TCM_INVALID_CDB_FIELD;
397
398 if (cmd->data_length == 0) {
399 target_complete_cmd(cmd, SAM_STAT_GOOD);
400 return 0;
401 }
402
394 if (cmd->data_length < 8) { 403 if (cmd->data_length < 8) {
395 pr_warn("UNMAP parameter list length %u too small\n", 404 pr_warn("UNMAP parameter list length %u too small\n",
396 cmd->data_length); 405 cmd->data_length);
397 return TCM_INVALID_PARAMETER_LIST; 406 return TCM_PARAMETER_LIST_LENGTH_ERROR;
398 } 407 }
399 408
400 buf = transport_kmap_data_sg(cmd); 409 buf = transport_kmap_data_sg(cmd);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 96b64d57ebbb..2030b608136d 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1517,6 +1517,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
1517 case TCM_UNSUPPORTED_SCSI_OPCODE: 1517 case TCM_UNSUPPORTED_SCSI_OPCODE:
1518 case TCM_INVALID_CDB_FIELD: 1518 case TCM_INVALID_CDB_FIELD:
1519 case TCM_INVALID_PARAMETER_LIST: 1519 case TCM_INVALID_PARAMETER_LIST:
1520 case TCM_PARAMETER_LIST_LENGTH_ERROR:
1520 case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: 1521 case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
1521 case TCM_UNKNOWN_MODE_PAGE: 1522 case TCM_UNKNOWN_MODE_PAGE:
1522 case TCM_WRITE_PROTECTED: 1523 case TCM_WRITE_PROTECTED:
@@ -2677,6 +2678,15 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
2677 /* INVALID FIELD IN PARAMETER LIST */ 2678 /* INVALID FIELD IN PARAMETER LIST */
2678 buffer[SPC_ASC_KEY_OFFSET] = 0x26; 2679 buffer[SPC_ASC_KEY_OFFSET] = 0x26;
2679 break; 2680 break;
2681 case TCM_PARAMETER_LIST_LENGTH_ERROR:
2682 /* CURRENT ERROR */
2683 buffer[0] = 0x70;
2684 buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
2685 /* ILLEGAL REQUEST */
2686 buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
2687 /* PARAMETER LIST LENGTH ERROR */
2688 buffer[SPC_ASC_KEY_OFFSET] = 0x1a;
2689 break;
2680 case TCM_UNEXPECTED_UNSOLICITED_DATA: 2690 case TCM_UNEXPECTED_UNSOLICITED_DATA:
2681 /* CURRENT ERROR */ 2691 /* CURRENT ERROR */
2682 buffer[0] = 0x70; 2692 buffer[0] = 0x70;
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index df14dce59191..c4af592f7057 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -195,6 +195,7 @@ enum tcm_sense_reason_table {
195 TCM_RESERVATION_CONFLICT = R(0x10), 195 TCM_RESERVATION_CONFLICT = R(0x10),
196 TCM_ADDRESS_OUT_OF_RANGE = R(0x11), 196 TCM_ADDRESS_OUT_OF_RANGE = R(0x11),
197 TCM_OUT_OF_RESOURCES = R(0x12), 197 TCM_OUT_OF_RESOURCES = R(0x12),
198 TCM_PARAMETER_LIST_LENGTH_ERROR = R(0x13),
198#undef R 199#undef R
199}; 200};
200 201